From a946317fab9776754192f679f38cb7789050c52d Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Tue, 27 Feb 2018 15:39:39 +0100 Subject: [PATCH 01/88] Filter: Converted static global variables to a filter_state struct. The static filter state was messy and blocked the planned parallel execution of filters. Anyway, this will be also slower as the state structure must be passed almost everywhere with us. --- filter/filter.c | 189 ++++++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 93 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 37cf16a3..1e608138 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -50,6 +50,16 @@ #define CMP_ERROR 999 +/* Internal filter state, to be allocated on stack when executing filters */ +struct filter_state { + struct rte **rte; + struct rta *old_rta; + struct ea_list **eattrs; + struct linpool *pool; + struct buffer buf; + int flags; +}; + void (*bt_assert_hook)(int result, struct f_inst *assert); static struct adata undef_adata; /* adata of length 0 used for undefined */ @@ -536,65 +546,59 @@ val_format(struct f_val v, buffer *buf) } } -static struct rte **f_rte; -static struct rta *f_old_rta; -static struct ea_list **f_eattrs; -static struct linpool *f_pool; -static struct buffer f_buf; -static int f_flags; -static inline void f_cache_eattrs(void) +static inline void f_cache_eattrs(struct filter_state *fs) { - f_eattrs = &((*f_rte)->attrs->eattrs); + fs->eattrs = &((*fs->rte)->attrs->eattrs); } -static inline void f_rte_cow(void) +static inline void f_rte_cow(struct filter_state *fs) { - if (!((*f_rte)->flags & REF_COW)) + if (!((*fs->rte)->flags & REF_COW)) return; - *f_rte = rte_do_cow(*f_rte); + *fs->rte = rte_cow(*fs->rte); } /* * rta_cow - prepare rta for modification by filter */ static void -f_rta_cow(void) +f_rta_cow(struct filter_state *fs) { - if (!rta_is_cached((*f_rte)->attrs)) + if (!rta_is_cached((*fs->rte)->attrs)) return; /* Prepare to modify rte */ - f_rte_cow(); + f_rte_cow(fs); /* Store old rta to free it later, it stores reference from rte_cow() */ - f_old_rta = (*f_rte)->attrs; + fs->old_rta = (*fs->rte)->attrs; /* * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared - * with f_old_rta (they will be copied when the cached rta will be obtained + * with fs->old_rta (they will be copied when the cached rta will be obtained * at the end of f_run()), also the lock of hostentry is inherited (we * suppose hostentry is not changed by filters). */ - (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool); + (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool); /* Re-cache the ea_list */ - f_cache_eattrs(); + f_cache_eattrs(fs); } static char * -val_format_str(struct f_val v) { +val_format_str(struct filter_state *fs, struct f_val v) { buffer b; LOG_BUFFER_INIT(b); val_format(v, &b); - return lp_strdup(f_pool, b.start); + return lp_strdup(fs->pool, b.start); } static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define runtime(fmt, ...) do { \ - if (!(f_flags & FF_SILENT)) \ + if (!(fs->flags & FF_SILENT)) \ log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ res.type = T_RETURN; \ res.val.i = F_ERROR; \ @@ -609,21 +613,22 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; n, f_instruction_name(what->fi_code), t, v##n.type); #define INTERPRET(val, what_) \ - val = interpret(what_); \ + val = interpret(fs, what_); \ if (val.type & T_RETURN) \ return val; #define ACCESS_RTE \ - do { if (!f_rte) runtime("No route to access"); } while (0) + do { if (!fs->rte) runtime("No route to access"); } while (0) #define ACCESS_EATTRS \ - do { if (!f_eattrs) f_cache_eattrs(); } while (0) + do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) #define BITFIELD_MASK(what) \ (1u << (what->a2.i >> 24)) /** * interpret + * @fs: filter state * @what: filter to interpret * * Interpret given tree of filter instructions. This is core function @@ -640,7 +645,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; * memory managment. */ static struct f_val -interpret(struct f_inst *what) +interpret(struct filter_state *fs, struct f_inst *what) { struct symbol *sym; struct f_val v1, v2, v3, res = { .type = T_VOID }, *vp; @@ -761,7 +766,7 @@ interpret(struct f_inst *what) struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin; while (tt) { - *vv = lp_alloc(f_pool, sizeof(struct f_path_mask)); + *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); if (tt->kind == PM_ASN_EXPR) { struct f_val res; INTERPRET(res, (struct f_inst *) tt->val); @@ -895,7 +900,7 @@ interpret(struct f_inst *what) break; case FI_PRINT: ARG_ANY(1); - val_format(v1, &f_buf); + val_format(v1, &fs->buf); break; case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */ ARG(1, T_BOOL); @@ -912,8 +917,8 @@ interpret(struct f_inst *what) case FI_PRINT_AND_DIE: 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); + !(fs->flags & FF_SILENT)) + log_commit(*L_INFO, &fs->buf); switch (what->a2.i) { case F_QUITBIRD: @@ -935,14 +940,14 @@ interpret(struct f_inst *what) case FI_RTA_GET: /* rta access */ { ACCESS_RTE; - struct rta *rta = (*f_rte)->attrs; + struct rta *rta = (*fs->rte)->attrs; res.type = what->aux; switch (what->a2.i) { case SA_FROM: res.val.ip = rta->from; break; case SA_GW: res.val.ip = rta->nh.gw; break; - case SA_NET: res.val.net = (*f_rte)->net->n.addr; break; + case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break; case SA_PROTO: res.val.s = rta->src->proto->name; break; case SA_SOURCE: res.val.i = rta->source; break; case SA_SCOPE: res.val.i = rta->scope; break; @@ -961,9 +966,9 @@ interpret(struct f_inst *what) if (what->aux != v1.type) runtime( "Attempt to set static attribute to incompatible type" ); - f_rta_cow(); + f_rta_cow(fs); { - struct rta *rta = (*f_rte)->attrs; + struct rta *rta = (*fs->rte)->attrs; switch (what->a2.i) { @@ -1027,7 +1032,7 @@ interpret(struct f_inst *what) { u16 code = what->a2.i; int f_type = what->aux >> 8; - eattr *e = ea_find(*f_eattrs, code); + eattr *e = ea_find(*fs->eattrs, code); if (!e) { /* A special case: undefined as_path looks like empty as_path */ @@ -1114,7 +1119,7 @@ interpret(struct f_inst *what) ACCESS_EATTRS; ARG_ANY(1); { - struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); u16 code = what->a2.i; int f_type = what->aux >> 8; @@ -1151,7 +1156,7 @@ interpret(struct f_inst *what) if (v1.type != T_IP) runtime( "Setting ip attribute to non-ip value" ); int len = sizeof(ip_addr); - struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) + len); + struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); ad->length = len; (* (ip_addr *) ad->data) = v1.val.ip; l->attrs[0].u.ptr = ad; @@ -1166,7 +1171,7 @@ interpret(struct f_inst *what) runtime( "Setting bit in bitfield attribute to non-bool value" ); { /* First, we have to find the old value */ - eattr *e = ea_find(*f_eattrs, code); + eattr *e = ea_find(*fs->eattrs, code); u32 data = e ? e->u.data : 0; if (v1.val.i) @@ -1198,23 +1203,23 @@ interpret(struct f_inst *what) default: bug("Unknown type in e,S"); } - f_rta_cow(); - l->next = *f_eattrs; - *f_eattrs = l; + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; } break; case FI_PREF_GET: ACCESS_RTE; res.type = T_INT; - res.val.i = (*f_rte)->pref; + res.val.i = (*fs->rte)->pref; break; case FI_PREF_SET: ACCESS_RTE; 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; + f_rte_cow(fs); + (*fs->rte)->pref = v1.val.i; break; case FI_LENGTH: /* Get length of */ ARG_ANY(1); @@ -1235,7 +1240,7 @@ interpret(struct f_inst *what) { net_addr_ip6_sadr *net = (void *) v1.val.net; - net_addr *src = lp_alloc(f_pool, sizeof(net_addr_ip6)); + net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); net_fill_ip6(src, net->src_prefix, net->src_pxlen); res.type = T_NET; @@ -1304,7 +1309,7 @@ interpret(struct f_inst *what) return res; case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */ ARG_ANY(1); - res = interpret(what->a2.p); + res = interpret(fs, what->a2.p); if (res.type == T_RETURN) return res; res.type &= ~T_RETURN; @@ -1342,14 +1347,14 @@ interpret(struct f_inst *what) case FI_EMPTY: /* Create empty attribute */ res.type = what->aux; - res.val.ad = adata_empty(f_pool, 0); + res.val.ad = adata_empty(fs->pool, 0); break; case FI_PATH_PREPEND: /* Path prepend */ 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); + res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); break; case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */ @@ -1380,7 +1385,7 @@ interpret(struct f_inst *what) runtime("Can't filter integer"); res.type = T_PATH; - res.val.ad = as_path_filter(f_pool, v1.val.ad, set, key, pos); + res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos); } else if (v1.type == T_CLIST) { @@ -1408,22 +1413,22 @@ interpret(struct f_inst *what) if (arg_set == 1) runtime("Can't add set"); else if (!arg_set) - res.val.ad = int_set_add(f_pool, v1.val.ad, n); + res.val.ad = int_set_add(fs->pool, v1.val.ad, n); else - res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad); + res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) - res.val.ad = int_set_del(f_pool, v1.val.ad, n); + res.val.ad = int_set_del(fs->pool, v1.val.ad, n); else - res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0); + res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0); break; case 'f': if (!arg_set) runtime("Can't filter pair"); - res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1); + res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1); break; default: @@ -1450,22 +1455,22 @@ interpret(struct f_inst *what) if (arg_set == 1) runtime("Can't add set"); else if (!arg_set) - res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec); + res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec); else - res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad); + res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) - res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec); + res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec); else - res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0); + res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0); break; case 'f': if (!arg_set) runtime("Can't filter ec"); - res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1); + res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1); break; default: @@ -1492,22 +1497,22 @@ interpret(struct f_inst *what) if (arg_set == 1) runtime("Can't add set"); else if (!arg_set) - res.val.ad = lc_set_add(f_pool, v1.val.ad, v2.val.lc); + res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc); else - res.val.ad = lc_set_union(f_pool, v1.val.ad, v2.val.ad); + res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) - res.val.ad = lc_set_del(f_pool, v1.val.ad, v2.val.lc); + res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc); else - res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 0); + res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0); break; case 'f': if (!arg_set) runtime("Can't filter lc"); - res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 1); + res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1); break; default: @@ -1531,11 +1536,11 @@ interpret(struct f_inst *what) { ACCESS_RTE; ACCESS_EATTRS; - v1.val.net = (*f_rte)->net->n.addr; + v1.val.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(*f_eattrs, EA_CODE(PROTOCOL_BGP, 0x02)); + 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"); @@ -1563,7 +1568,7 @@ interpret(struct f_inst *what) ARG_ANY(1); res.type = T_STRING; - res.val.s = val_format_str(v1); + res.val.s = val_format_str(fs, v1); break; case FI_ASSERT: /* Birdtest Assert */ @@ -1765,38 +1770,38 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla int rte_cow = ((*rte)->flags & REF_COW); DBG( "Running filter `%s'...", filter->name ); - f_rte = rte; - f_eattrs = NULL; - f_old_rta = NULL; - f_pool = tmp_pool; - f_flags = flags; + struct filter_state fs = { + .rte = rte, + .pool = tmp_pool, + .flags = flags, + }; - LOG_BUFFER_INIT(f_buf); + LOG_BUFFER_INIT(fs.buf); - struct f_val res = interpret(filter->root); + struct f_val res = interpret(&fs, filter->root); - if (f_old_rta) { + if (fs.old_rta) { /* - * Cached rta was modified and f_rte contains now an uncached one, + * Cached rta was modified and fs->rte contains now an uncached one, * sharing some part with the cached one. The cached rta should - * be freed (if rte was originally COW, f_old_rta is a clone + * be freed (if rte was originally COW, fs->old_rta is a clone * obtained during rte_cow()). * * This also implements the exception mentioned in f_run() * description. The reason for this is that rta reuses parts of - * f_old_rta, and these may be freed during rta_free(f_old_rta). + * fs->old_rta, and these may be freed during rta_free(fs->old_rta). * This is not the problem if rte was COW, because original rte * also holds the same rta. */ if (!rte_cow) - (*f_rte)->attrs = rta_lookup((*f_rte)->attrs); + (*fs.rte)->attrs = rta_lookup((*fs.rte)->attrs); - rta_free(f_old_rta); + rta_free(fs.old_rta); } if (res.type != T_RETURN) { - if (!(f_flags & FF_SILENT)) + if (!(fs.flags & FF_SILENT)) log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); return F_ERROR; } @@ -1810,16 +1815,15 @@ struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) { - f_rte = rte; - f_eattrs = NULL; - f_old_rta = NULL; - f_pool = tmp_pool; - f_flags = 0; + struct filter_state fs = { + .rte = rte, + .pool = tmp_pool, + }; - LOG_BUFFER_INIT(f_buf); + LOG_BUFFER_INIT(fs.buf); /* Note that in this function we assume that rte->attrs is private / uncached */ - struct f_val res = interpret(expr); + struct f_val res = interpret(&fs, expr); return res; } @@ -1827,14 +1831,13 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool) { - f_flags = 0; - f_eattrs = NULL; - f_rte = NULL; - f_pool = tmp_pool; + struct filter_state fs = { + .pool = tmp_pool, + }; - LOG_BUFFER_INIT(f_buf); + LOG_BUFFER_INIT(fs.buf); - return interpret(expr); + return interpret(&fs, expr); } uint From 02dcbf343d94dd548605c5efbf724f89d81d7258 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 12:45:21 +0100 Subject: [PATCH 02/88] Configure: Don't check for implicit fallthrough unless when debugging. --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index da1a8f44..33bc9101 100644 --- a/configure.ac +++ b/configure.ac @@ -364,6 +364,9 @@ if test "$enable_debug" = yes ; then AC_CHECK_LIB([efence], [malloc]) fi fi +else + BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough]) + BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough]) fi CLIENT=birdcl From aca8263926df6156322e1a1157886f1cad2486b1 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 12:48:33 +0100 Subject: [PATCH 03/88] Filter refactoring: Moved the interpret macros inside the block --- filter/filter.c | 61 ++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 1e608138..f5efe894 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -597,32 +597,6 @@ val_format_str(struct filter_state *fs, struct f_val v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -#define runtime(fmt, ...) do { \ - if (!(fs->flags & FF_SILENT)) \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ - res.type = T_RETURN; \ - res.val.i = F_ERROR; \ - return res; \ - } while(0) - -#define ARG_ANY(n) INTERPRET(v##n, what->a##n.p) - -#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 INTERPRET(val, what_) \ - val = interpret(fs, what_); \ - if (val.type & T_RETURN) \ - return val; - -#define ACCESS_RTE \ - do { if (!fs->rte) runtime("No route to access"); } while (0) - -#define ACCESS_EATTRS \ - do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) - #define BITFIELD_MASK(what) \ (1u << (what->a2.i >> 24)) @@ -656,6 +630,32 @@ interpret(struct filter_state *fs, struct f_inst *what) for ( ; what; what = what->next) { res.type = T_VOID; switch(what->fi_code) { +#define runtime(fmt, ...) do { \ + if (!(fs->flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + res.type = T_RETURN; \ + res.val.i = F_ERROR; \ + return res; \ + } while(0) + +#define ARG_ANY(n) INTERPRET(v##n, what->a##n.p) + +#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 INTERPRET(val, what_) \ + val = interpret(fs, what_); \ + if (val.type & T_RETURN) \ + return val; + +#define ACCESS_RTE \ + do { if (!fs->rte) runtime("No route to access"); } while (0) + +#define ACCESS_EATTRS \ + do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) + /* Binary operators */ case FI_ADD: ARG(1,T_INT); @@ -1582,12 +1582,17 @@ interpret(struct filter_state *fs, struct f_inst *what) default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); + +#undef runtime +#undef ARG_ANY +#undef ARG +#undef INTERPRET +#undef ACCESS_RTE +#undef ACCESS_EATTRS }} return res; } -#undef ARG -#undef ARG_ANY #define ARG(n) \ if (!i_same(f1->a##n.p, f2->a##n.p)) \ From 25566c68109381178e0305f3e7e1464dea15b90b Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 12:58:01 +0100 Subject: [PATCH 04/88] Filter refactoring: Moved the bitfield bit position formula to route.h --- filter/filter.c | 5 ++--- nest/route.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index f5efe894..5829fd51 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -597,9 +597,6 @@ val_format_str(struct filter_state *fs, struct f_val v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -#define BITFIELD_MASK(what) \ - (1u << (what->a2.i >> 24)) - /** * interpret * @fs: filter state @@ -656,6 +653,8 @@ interpret(struct filter_state *fs, struct f_inst *what) #define ACCESS_EATTRS \ do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) +#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a2.i)) + /* Binary operators */ case FI_ADD: ARG(1,T_INT); diff --git a/nest/route.h b/nest/route.h index 8dfbb376..74446f48 100644 --- a/nest/route.h +++ b/nest/route.h @@ -493,6 +493,7 @@ const char *ea_custom_name(uint ea); #define EA_CUSTOM_BIT 0x8000 #define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */ #define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */ +#define EA_BIT_GET(ea) ((ea) >> 24) #define EAF_TYPE_MASK 0x1f /* Mask with this to get type */ #define EAF_TYPE_INT 0x01 /* 32-bit unsigned integer number */ From f62a369fb48be066560d6e8f0df82eef9c464ef0 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 13:08:08 +0100 Subject: [PATCH 05/88] Filter refactoring: Moved filter instruction definition to a separate file --- filter/f-inst.c | 937 ++++++++++++++++++++++++++++++++++++++++++++++++ filter/filter.c | 927 +---------------------------------------------- 2 files changed, 938 insertions(+), 926 deletions(-) create mode 100644 filter/f-inst.c diff --git a/filter/f-inst.c b/filter/f-inst.c new file mode 100644 index 00000000..24908442 --- /dev/null +++ b/filter/f-inst.c @@ -0,0 +1,937 @@ +/* + * Filters: Instructions themselves + * + * Copyright 1998 Pavel Machek + * Copyright 2018 Maria Matejka + * Copyright 2018 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + * + */ + +/* Binary operators */ + case FI_ADD: + 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: + 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: + 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: + 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(1,T_BOOL); + if (v1.val.i == (what->fi_code == FI_OR)) { + res.type = T_BOOL; + res.val.i = v1.val.i; + } else { + ARG(2,T_BOOL); + res = v2; + } + break; + case FI_PAIR_CONSTRUCT: + ARG(1,T_INT); + ARG(2,T_INT); + u1 = v1.val.i; + u2 = v2.val.i; + if ((u1 > 0xFFFF) || (u2 > 0xFFFF)) + runtime( "Can't operate with value out of bounds in pair constructor" ); + res.val.i = (u1 << 16) | u2; + res.type = T_PAIR; + break; + + case FI_EC_CONSTRUCT: + { + ARG_ANY(1); + ARG(2, T_INT); + + int check, ipv4_used; + u32 key, val; + + if (v1.type == T_INT) { + ipv4_used = 0; key = v1.val.i; + } + else if (v1.type == T_QUAD) { + ipv4_used = 1; key = v1.val.i; + } + /* IP->Quad implicit conversion */ + else if (val_is_ip4(v1)) { + ipv4_used = 1; key = ipa_to_u32(v1.val.ip); + } + else + runtime("Can't operate with key of non-integer/IPv4 type in EC constructor"); + + val = v2.val.i; + + /* XXXX */ + res.type = T_EC; + + if (what->aux == EC_GENERIC) { + check = 0; res.val.ec = ec_generic(key, val); + } + else if (ipv4_used) { + check = 1; res.val.ec = ec_ip4(what->aux, key, val); + } + else if (key < 0x10000) { + check = 0; res.val.ec = ec_as2(what->aux, key, val); + } + else { + check = 1; res.val.ec = ec_as4(what->aux, key, val); + } + + if (check && (val > 0xFFFF)) + runtime("Can't operate with value out of bounds in EC constructor"); + + break; + } + + case FI_LC_CONSTRUCT: + { + 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 }; + + break; + } + + case FI_PATHMASK_CONSTRUCT: + { + struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin; + + while (tt) { + *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); + if (tt->kind == PM_ASN_EXPR) { + struct f_val res; + INTERPRET(res, (struct f_inst *) tt->val); + (*vv)->kind = PM_ASN; + if (res.type != T_INT) { + runtime( "Error resolving path mask template: value not an integer" ); + return (struct f_val) { .type = T_VOID }; + } + + (*vv)->val = res.val.i; + } else { + **vv = *tt; + } + tt = tt->next; + vv = &((*vv)->next); + } + + res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin }; + break; + } + +/* Relational operators */ + +#define COMPARE(x) \ + ARG_ANY(1); \ + ARG_ANY(2); \ + i = val_compare(v1, v2); \ + if (i==CMP_ERROR) \ + runtime( "Can't compare values of incompatible types" ); \ + res.type = T_BOOL; \ + res.val.i = (x); \ + break; + +#define SAME(x) \ + ARG_ANY(1); \ + ARG_ANY(2); \ + i = val_same(v1, v2); \ + res.type = T_BOOL; \ + res.val.i = (x); \ + break; + + case FI_NEQ: SAME(!i); + case FI_EQ: SAME(i); + case FI_LT: COMPARE(i==-1); + case FI_LTE: COMPARE(i!=1); + + case FI_NOT: + ARG(1,T_BOOL); + res = v1; + res.val.i = !res.val.i; + break; + + case FI_MATCH: + ARG_ANY(1); + ARG_ANY(2); + res.type = T_BOOL; + res.val.i = val_in_range(v1, v2); + if (res.val.i == CMP_ERROR) + runtime( "~ applied on unknown type pair" ); + res.val.i = !!res.val.i; + break; + + case FI_NOT_MATCH: + ARG_ANY(1); + ARG_ANY(2); + res.type = T_BOOL; + res.val.i = val_in_range(v1, v2); + if (res.val.i == CMP_ERROR) + runtime( "!~ applied on unknown type pair" ); + res.val.i = !res.val.i; + break; + + case FI_DEFINED: + ARG_ANY(1); + res.type = T_BOOL; + res.val.i = (v1.type != T_VOID) && !undef_value(v1); + break; + case FI_TYPE: + ARG_ANY(1); /* There may be more types supporting this operation */ + 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 FI_IS_V4: + 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_ANY(2); + sym = what->a1.p; + vp = sym->def; + if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) + { + /* IP->Quad implicit conversion */ + if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(v2)) + { + vp->type = T_QUAD; + vp->val.i = ipa_to_u32(v2.val.ip); + break; + } + runtime( "Assigning to variable of incompatible type" ); + } + *vp = v2; + break; + + /* some constants have value in a2, some in *a1.p, strange. */ + case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */ + res.type = what->aux; + + if (res.type == T_PREFIX_SET) + res.val.ti = what->a2.p; + else if (res.type == T_SET) + res.val.t = what->a2.p; + else if (res.type == T_STRING) + res.val.s = what->a2.p; + else + res.val.i = what->a2.i; + break; + case FI_VARIABLE: + case FI_CONSTANT_INDIRECT: + res = * ((struct f_val *) what->a1.p); + break; + case FI_PRINT: + ARG_ANY(1); + val_format(v1, &fs->buf); + break; + case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */ + ARG(1, T_BOOL); + if (v1.val.i) { + ARG_ANY(2); + res.val.i = 0; + } else + res.val.i = 1; + res.type = T_BOOL; + break; + case FI_NOP: + debug( "No operation\n" ); + break; + case FI_PRINT_AND_DIE: + ARG_ANY(1); + if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && + !(fs->flags & FF_SILENT)) + log_commit(*L_INFO, &fs->buf); + + switch (what->a2.i) { + case F_QUITBIRD: + die( "Filter asked me to die" ); + 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 */ + res.type = T_RETURN; + res.val.i = what->a2.i; + return res; /* We have to return now, no more processing. */ + case F_NONL: + case F_NOP: + break; + default: + bug( "unknown return type: Can't happen"); + } + break; + case FI_RTA_GET: /* rta access */ + { + ACCESS_RTE; + struct rta *rta = (*fs->rte)->attrs; + res.type = what->aux; + + switch (what->a2.i) + { + case SA_FROM: res.val.ip = rta->from; break; + case SA_GW: res.val.ip = rta->nh.gw; break; + case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break; + case SA_PROTO: res.val.s = rta->src->proto->name; break; + case SA_SOURCE: res.val.i = rta->source; break; + case SA_SCOPE: res.val.i = rta->scope; break; + case SA_DEST: res.val.i = rta->dest; break; + case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break; + case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break; + + default: + bug("Invalid static attribute access (%x)", res.type); + } + } + break; + case FI_RTA_SET: + ACCESS_RTE; + ARG_ANY(1); + if (what->aux != v1.type) + runtime( "Attempt to set static attribute to incompatible type" ); + + f_rta_cow(fs); + { + struct rta *rta = (*fs->rte)->attrs; + + switch (what->a2.i) + { + case SA_FROM: + rta->from = v1.val.ip; + break; + + case SA_GW: + { + ip_addr ip = v1.val.ip; + neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = ip; + rta->nh.iface = n->iface; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + case SA_SCOPE: + rta->scope = v1.val.i; + break; + + case SA_DEST: + i = v1.val.i; + if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) + runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + + rta->dest = i; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; + rta->hostentry = NULL; + break; + + case SA_IFNAME: + { + struct iface *ifa = if_find_by_name(v1.val.s); + if (!ifa) + runtime( "Invalid iface name" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = IPA_NONE; + rta->nh.iface = ifa; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + default: + bug("Invalid static attribute access (%x)", res.type); + } + } + break; + case FI_EA_GET: /* Access to extended attributes */ + ACCESS_RTE; + ACCESS_EATTRS; + { + u16 code = what->a2.i; + int f_type = what->aux >> 8; + eattr *e = ea_find(*fs->eattrs, code); + + if (!e) { + /* A special case: undefined as_path looks like empty as_path */ + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) { + res.type = T_PATH; + res.val.ad = &undef_adata; + break; + } + + /* The same special case for int_set */ + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) { + res.type = T_CLIST; + res.val.ad = &undef_adata; + break; + } + + /* The same special case for ec_set */ + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { + res.type = T_ECLIST; + res.val.ad = &undef_adata; + break; + } + + /* The same special case for lc_set */ + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) { + res.type = T_LCLIST; + res.val.ad = &undef_adata; + break; + } + + /* Undefined value */ + res.type = T_VOID; + break; + } + + switch (e->type & EAF_TYPE_MASK) { + case EAF_TYPE_INT: + res.type = f_type; + res.val.i = e->u.data; + break; + case EAF_TYPE_ROUTER_ID: + res.type = T_QUAD; + res.val.i = e->u.data; + break; + case EAF_TYPE_OPAQUE: + res.type = T_ENUM_EMPTY; + res.val.i = 0; + break; + case EAF_TYPE_IP_ADDRESS: + res.type = T_IP; + struct adata * ad = e->u.ptr; + res.val.ip = * (ip_addr *) ad->data; + break; + case EAF_TYPE_AS_PATH: + res.type = T_PATH; + res.val.ad = e->u.ptr; + break; + case EAF_TYPE_BITFIELD: + res.type = T_BOOL; + res.val.i = !!(e->u.data & BITFIELD_MASK(what)); + break; + case EAF_TYPE_INT_SET: + res.type = T_CLIST; + res.val.ad = e->u.ptr; + break; + case EAF_TYPE_EC_SET: + res.type = T_ECLIST; + res.val.ad = e->u.ptr; + break; + case EAF_TYPE_LC_SET: + res.type = T_LCLIST; + res.val.ad = e->u.ptr; + break; + case EAF_TYPE_UNDEF: + res.type = T_VOID; + break; + default: + bug("Unknown type in e,a"); + } + } + break; + case FI_EA_SET: + ACCESS_RTE; + ACCESS_EATTRS; + ARG_ANY(1); + { + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + u16 code = what->a2.i; + int f_type = what->aux >> 8; + + l->next = NULL; + l->flags = EALF_SORTED; + l->count = 1; + l->attrs[0].id = code; + l->attrs[0].flags = 0; + l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH; + + switch (what->aux & EAF_TYPE_MASK) { + case EAF_TYPE_INT: + if (v1.type != 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; + + case EAF_TYPE_OPAQUE: + 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" ); + int len = sizeof(ip_addr); + struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); + ad->length = len; + (* (ip_addr *) ad->data) = v1.val.ip; + l->attrs[0].u.ptr = ad; + break; + case EAF_TYPE_AS_PATH: + if (v1.type != T_PATH) + runtime( "Setting path attribute to non-path value" ); + 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, code); + u32 data = e ? e->u.data : 0; + + if (v1.val.i) + l->attrs[0].u.data = data | BITFIELD_MASK(what); + else + l->attrs[0].u.data = data & ~BITFIELD_MASK(what);; + } + 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; + case EAF_TYPE_UNDEF: + if (v1.type != T_VOID) + runtime( "Setting void attribute to non-void value" ); + l->attrs[0].u.data = 0; + break; + default: bug("Unknown type in e,S"); + } + + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; + } + break; + case FI_PREF_GET: + ACCESS_RTE; + res.type = T_INT; + res.val.i = (*fs->rte)->pref; + break; + case FI_PREF_SET: + ACCESS_RTE; + ARG(1,T_INT); + if (v1.val.i > 0xFFFF) + runtime( "Setting preference value out of bounds" ); + f_rte_cow(fs); + (*fs->rte)->pref = v1.val.i; + break; + case FI_LENGTH: /* Get length of */ + ARG_ANY(1); + res.type = T_INT; + switch(v1.type) { + case T_NET: res.val.i = net_pxlen(v1.val.net); break; + case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; + case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break; + case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break; + case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break; + default: runtime( "Prefix, path, clist or eclist expected" ); + } + break; + case FI_SADR_SRC: /* Get SADR 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 *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); + net_fill_ip6(src, net->src_prefix, net->src_pxlen); + + res.type = T_NET; + res.val.net = src; + } + break; + case FI_ROA_MAXLEN: /* Get ROA max prefix length */ + ARG(1, T_NET); + if (!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 FI_ROA_ASN: /* Get ROA ASN */ + ARG(1, T_NET); + if (!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 FI_IP: /* Convert prefix to ... */ + ARG(1, T_NET); + res.type = T_IP; + res.val.ip = net_prefix(v1.val.net); + break; + case FI_ROUTE_DISTINGUISHER: + 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 */ + ARG(1, T_PATH); + + as = 0; + as_path_get_first(v1.val.ad, &as); + res.type = T_INT; + res.val.i = as; + break; + case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */ + ARG(1, T_PATH); + + as = 0; + as_path_get_last(v1.val.ad, &as); + res.type = T_INT; + res.val.i = as; + break; + case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */ + ARG(1, T_PATH); + + res.type = T_INT; + res.val.i = as_path_get_last_nonaggregated(v1.val.ad); + break; + case FI_RETURN: + 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 */ + ARG_ANY(1); + res = interpret(fs, what->a2.p); + if (res.type == T_RETURN) + return res; + res.type &= ~T_RETURN; + break; + case FI_CLEAR_LOCAL_VARS: /* Clear local variables */ + for (sym = what->a1.p; sym != NULL; sym = sym->aux2) + ((struct f_val *) sym->def)->type = T_VOID; + break; + case FI_SWITCH: + ARG_ANY(1); + { + struct f_tree *t = find_tree(what->a2.p, v1); + if (!t) { + v1.type = T_VOID; + t = find_tree(what->a2.p, v1); + if (!t) { + debug( "No else statement?\n"); + break; + } + } + /* It is actually possible to have t->data NULL */ + + INTERPRET(res, t->data); + } + break; + case FI_IP_MASK: /* IP.MASK(val) */ + ARG(1, T_IP); + ARG(2, T_INT); + + 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 FI_EMPTY: /* Create empty attribute */ + res.type = what->aux; + res.val.ad = adata_empty(fs->pool, 0); + break; + case FI_PATH_PREPEND: /* Path prepend */ + ARG(1, T_PATH); + ARG(2, T_INT); + + res.type = T_PATH; + res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); + break; + + case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */ + ARG_ANY(1); + ARG_ANY(2); + if (v1.type == T_PATH) + { + struct f_tree *set = NULL; + u32 key = 0; + int pos; + + if (v2.type == T_INT) + key = v2.val.i; + else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT)) + set = v2.val.t; + else + runtime("Can't delete non-integer (set)"); + + switch (what->aux) + { + case 'a': runtime("Can't add to path"); + case 'd': pos = 0; break; + case 'f': pos = 1; break; + default: bug("unknown Ca operation"); + } + + if (pos && !set) + runtime("Can't filter integer"); + + res.type = T_PATH; + res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos); + } + else if (v1.type == T_CLIST) + { + /* Community (or cluster) list */ + struct f_val dummy; + int arg_set = 0; + uint n = 0; + + if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) + n = v2.val.i; + /* IP->Quad implicit conversion */ + else if (val_is_ip4(v2)) + n = ipa_to_u32(v2.val.ip); + else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy)) + arg_set = 1; + else if (v2.type == T_CLIST) + arg_set = 2; + else + runtime("Can't add/delete non-pair"); + + res.type = T_CLIST; + switch (what->aux) + { + case 'a': + if (arg_set == 1) + runtime("Can't add set"); + else if (!arg_set) + res.val.ad = int_set_add(fs->pool, v1.val.ad, n); + else + res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad); + break; + + case 'd': + if (!arg_set) + res.val.ad = int_set_del(fs->pool, v1.val.ad, n); + else + res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0); + break; + + case 'f': + if (!arg_set) + runtime("Can't filter pair"); + res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1); + break; + + default: + bug("unknown Ca operation"); + } + } + else if (v1.type == T_ECLIST) + { + /* Extended community list */ + int arg_set = 0; + + /* v2.val is either EC or EC-set */ + if ((v2.type == T_SET) && eclist_set_type(v2.val.t)) + arg_set = 1; + else if (v2.type == T_ECLIST) + arg_set = 2; + else if (v2.type != T_EC) + runtime("Can't add/delete non-ec"); + + res.type = T_ECLIST; + switch (what->aux) + { + case 'a': + if (arg_set == 1) + runtime("Can't add set"); + else if (!arg_set) + res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec); + else + res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad); + break; + + case 'd': + if (!arg_set) + res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec); + else + res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0); + break; + + case 'f': + if (!arg_set) + runtime("Can't filter ec"); + res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1); + break; + + default: + bug("unknown Ca operation"); + } + } + else if (v1.type == T_LCLIST) + { + /* Large community list */ + int arg_set = 0; + + /* v2.val is either LC or LC-set */ + if ((v2.type == T_SET) && lclist_set_type(v2.val.t)) + arg_set = 1; + else if (v2.type == T_LCLIST) + arg_set = 2; + else if (v2.type != T_LC) + runtime("Can't add/delete non-lc"); + + res.type = T_LCLIST; + switch (what->aux) + { + case 'a': + if (arg_set == 1) + runtime("Can't add set"); + else if (!arg_set) + res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc); + else + res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad); + break; + + case 'd': + if (!arg_set) + res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc); + else + res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0); + break; + + case 'f': + if (!arg_set) + runtime("Can't filter lc"); + res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1); + break; + + default: + bug("unknown Ca operation"); + } + } + else + runtime("Can't add/delete to non-[e|l]clist"); + + break; + + case FI_ROA_CHECK: /* ROA Check */ + if (what->arg1) + { + ARG(1, T_NET); + ARG(2, T_INT); + + as = v2.val.i; + } + else + { + ACCESS_RTE; + ACCESS_EATTRS; + v1.val.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"); + + as_path_get_last(e->u.ptr, &as); + } + + 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; + + 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 FI_FORMAT: /* Format */ + ARG_ANY(1); + + res.type = T_STRING; + res.val.s = val_format_str(fs, v1); + break; + + case FI_ASSERT: /* Birdtest Assert */ + ARG(1, T_BOOL); + + res.type = v1.type; + res.val = v1.val; + + CALL(bt_assert_hook, res.val.i, what); + break; + + default: + bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); diff --git a/filter/filter.c b/filter/filter.c index 5829fd51..794e35e8 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -655,932 +655,7 @@ interpret(struct filter_state *fs, struct f_inst *what) #define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a2.i)) -/* Binary operators */ - case FI_ADD: - 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: - 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: - 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: - 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(1,T_BOOL); - if (v1.val.i == (what->fi_code == FI_OR)) { - res.type = T_BOOL; - res.val.i = v1.val.i; - } else { - ARG(2,T_BOOL); - res = v2; - } - break; - case FI_PAIR_CONSTRUCT: - ARG(1,T_INT); - ARG(2,T_INT); - u1 = v1.val.i; - u2 = v2.val.i; - if ((u1 > 0xFFFF) || (u2 > 0xFFFF)) - runtime( "Can't operate with value out of bounds in pair constructor" ); - res.val.i = (u1 << 16) | u2; - res.type = T_PAIR; - break; - - case FI_EC_CONSTRUCT: - { - ARG_ANY(1); - ARG(2, T_INT); - - int check, ipv4_used; - u32 key, val; - - if (v1.type == T_INT) { - ipv4_used = 0; key = v1.val.i; - } - else if (v1.type == T_QUAD) { - ipv4_used = 1; key = v1.val.i; - } - /* IP->Quad implicit conversion */ - else if (val_is_ip4(v1)) { - ipv4_used = 1; key = ipa_to_u32(v1.val.ip); - } - else - runtime("Can't operate with key of non-integer/IPv4 type in EC constructor"); - - val = v2.val.i; - - /* XXXX */ - res.type = T_EC; - - if (what->aux == EC_GENERIC) { - check = 0; res.val.ec = ec_generic(key, val); - } - else if (ipv4_used) { - check = 1; res.val.ec = ec_ip4(what->aux, key, val); - } - else if (key < 0x10000) { - check = 0; res.val.ec = ec_as2(what->aux, key, val); - } - else { - check = 1; res.val.ec = ec_as4(what->aux, key, val); - } - - if (check && (val > 0xFFFF)) - runtime("Can't operate with value out of bounds in EC constructor"); - - break; - } - - case FI_LC_CONSTRUCT: - { - 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 }; - - break; - } - - case FI_PATHMASK_CONSTRUCT: - { - struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin; - - while (tt) { - *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); - if (tt->kind == PM_ASN_EXPR) { - struct f_val res; - INTERPRET(res, (struct f_inst *) tt->val); - (*vv)->kind = PM_ASN; - if (res.type != T_INT) { - runtime( "Error resolving path mask template: value not an integer" ); - return (struct f_val) { .type = T_VOID }; - } - - (*vv)->val = res.val.i; - } else { - **vv = *tt; - } - tt = tt->next; - vv = &((*vv)->next); - } - - res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin }; - break; - } - -/* Relational operators */ - -#define COMPARE(x) \ - ARG_ANY(1); \ - ARG_ANY(2); \ - i = val_compare(v1, v2); \ - if (i==CMP_ERROR) \ - runtime( "Can't compare values of incompatible types" ); \ - res.type = T_BOOL; \ - res.val.i = (x); \ - break; - -#define SAME(x) \ - ARG_ANY(1); \ - ARG_ANY(2); \ - i = val_same(v1, v2); \ - res.type = T_BOOL; \ - res.val.i = (x); \ - break; - - case FI_NEQ: SAME(!i); - case FI_EQ: SAME(i); - case FI_LT: COMPARE(i==-1); - case FI_LTE: COMPARE(i!=1); - - case FI_NOT: - ARG(1,T_BOOL); - res = v1; - res.val.i = !res.val.i; - break; - - case FI_MATCH: - ARG_ANY(1); - ARG_ANY(2); - res.type = T_BOOL; - res.val.i = val_in_range(v1, v2); - if (res.val.i == CMP_ERROR) - runtime( "~ applied on unknown type pair" ); - res.val.i = !!res.val.i; - break; - - case FI_NOT_MATCH: - ARG_ANY(1); - ARG_ANY(2); - res.type = T_BOOL; - res.val.i = val_in_range(v1, v2); - if (res.val.i == CMP_ERROR) - runtime( "!~ applied on unknown type pair" ); - res.val.i = !res.val.i; - break; - - case FI_DEFINED: - ARG_ANY(1); - res.type = T_BOOL; - res.val.i = (v1.type != T_VOID) && !undef_value(v1); - break; - case FI_TYPE: - ARG_ANY(1); /* There may be more types supporting this operation */ - 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 FI_IS_V4: - 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_ANY(2); - sym = what->a1.p; - vp = sym->def; - if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) - { - /* IP->Quad implicit conversion */ - if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(v2)) - { - vp->type = T_QUAD; - vp->val.i = ipa_to_u32(v2.val.ip); - break; - } - runtime( "Assigning to variable of incompatible type" ); - } - *vp = v2; - break; - - /* some constants have value in a2, some in *a1.p, strange. */ - case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */ - res.type = what->aux; - - if (res.type == T_PREFIX_SET) - res.val.ti = what->a2.p; - else if (res.type == T_SET) - res.val.t = what->a2.p; - else if (res.type == T_STRING) - res.val.s = what->a2.p; - else - res.val.i = what->a2.i; - break; - case FI_VARIABLE: - case FI_CONSTANT_INDIRECT: - res = * ((struct f_val *) what->a1.p); - break; - case FI_PRINT: - ARG_ANY(1); - val_format(v1, &fs->buf); - break; - case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */ - ARG(1, T_BOOL); - if (v1.val.i) { - ARG_ANY(2); - res.val.i = 0; - } else - res.val.i = 1; - res.type = T_BOOL; - break; - case FI_NOP: - debug( "No operation\n" ); - break; - case FI_PRINT_AND_DIE: - ARG_ANY(1); - if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && - !(fs->flags & FF_SILENT)) - log_commit(*L_INFO, &fs->buf); - - switch (what->a2.i) { - case F_QUITBIRD: - die( "Filter asked me to die" ); - 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 */ - res.type = T_RETURN; - res.val.i = what->a2.i; - return res; /* We have to return now, no more processing. */ - case F_NONL: - case F_NOP: - break; - default: - bug( "unknown return type: Can't happen"); - } - break; - case FI_RTA_GET: /* rta access */ - { - ACCESS_RTE; - struct rta *rta = (*fs->rte)->attrs; - res.type = what->aux; - - switch (what->a2.i) - { - case SA_FROM: res.val.ip = rta->from; break; - case SA_GW: res.val.ip = rta->nh.gw; break; - case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break; - case SA_PROTO: res.val.s = rta->src->proto->name; break; - case SA_SOURCE: res.val.i = rta->source; break; - case SA_SCOPE: res.val.i = rta->scope; break; - case SA_DEST: res.val.i = rta->dest; break; - case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break; - case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break; - - default: - bug("Invalid static attribute access (%x)", res.type); - } - } - break; - case FI_RTA_SET: - ACCESS_RTE; - ARG_ANY(1); - if (what->aux != v1.type) - runtime( "Attempt to set static attribute to incompatible type" ); - - f_rta_cow(fs); - { - struct rta *rta = (*fs->rte)->attrs; - - switch (what->a2.i) - { - case SA_FROM: - rta->from = v1.val.ip; - break; - - case SA_GW: - { - ip_addr ip = v1.val.ip; - neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); - if (!n || (n->scope == SCOPE_HOST)) - runtime( "Invalid gw address" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = ip; - rta->nh.iface = n->iface; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - break; - - case SA_SCOPE: - rta->scope = v1.val.i; - break; - - case SA_DEST: - i = v1.val.i; - if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) - runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); - - rta->dest = i; - rta->nh.gw = IPA_NONE; - rta->nh.iface = NULL; - rta->nh.next = NULL; - rta->hostentry = NULL; - break; - - case SA_IFNAME: - { - struct iface *ifa = if_find_by_name(v1.val.s); - if (!ifa) - runtime( "Invalid iface name" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = IPA_NONE; - rta->nh.iface = ifa; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - break; - - default: - bug("Invalid static attribute access (%x)", res.type); - } - } - break; - case FI_EA_GET: /* Access to extended attributes */ - ACCESS_RTE; - ACCESS_EATTRS; - { - u16 code = what->a2.i; - int f_type = what->aux >> 8; - eattr *e = ea_find(*fs->eattrs, code); - - if (!e) { - /* A special case: undefined as_path looks like empty as_path */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) { - res.type = T_PATH; - res.val.ad = &undef_adata; - break; - } - - /* The same special case for int_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) { - res.type = T_CLIST; - res.val.ad = &undef_adata; - break; - } - - /* The same special case for ec_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { - res.type = T_ECLIST; - res.val.ad = &undef_adata; - break; - } - - /* The same special case for lc_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) { - res.type = T_LCLIST; - res.val.ad = &undef_adata; - break; - } - - /* Undefined value */ - res.type = T_VOID; - break; - } - - switch (e->type & EAF_TYPE_MASK) { - case EAF_TYPE_INT: - res.type = f_type; - res.val.i = e->u.data; - break; - case EAF_TYPE_ROUTER_ID: - res.type = T_QUAD; - res.val.i = e->u.data; - break; - case EAF_TYPE_OPAQUE: - res.type = T_ENUM_EMPTY; - res.val.i = 0; - break; - case EAF_TYPE_IP_ADDRESS: - res.type = T_IP; - struct adata * ad = e->u.ptr; - res.val.ip = * (ip_addr *) ad->data; - break; - case EAF_TYPE_AS_PATH: - res.type = T_PATH; - res.val.ad = e->u.ptr; - break; - case EAF_TYPE_BITFIELD: - res.type = T_BOOL; - res.val.i = !!(e->u.data & BITFIELD_MASK(what)); - break; - case EAF_TYPE_INT_SET: - res.type = T_CLIST; - res.val.ad = e->u.ptr; - break; - case EAF_TYPE_EC_SET: - res.type = T_ECLIST; - res.val.ad = e->u.ptr; - break; - case EAF_TYPE_LC_SET: - res.type = T_LCLIST; - res.val.ad = e->u.ptr; - break; - case EAF_TYPE_UNDEF: - res.type = T_VOID; - break; - default: - bug("Unknown type in e,a"); - } - } - break; - case FI_EA_SET: - ACCESS_RTE; - ACCESS_EATTRS; - ARG_ANY(1); - { - struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - u16 code = what->a2.i; - int f_type = what->aux >> 8; - - l->next = NULL; - l->flags = EALF_SORTED; - l->count = 1; - l->attrs[0].id = code; - l->attrs[0].flags = 0; - l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH; - - switch (what->aux & EAF_TYPE_MASK) { - case EAF_TYPE_INT: - if (v1.type != 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; - - case EAF_TYPE_OPAQUE: - 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" ); - int len = sizeof(ip_addr); - struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); - ad->length = len; - (* (ip_addr *) ad->data) = v1.val.ip; - l->attrs[0].u.ptr = ad; - break; - case EAF_TYPE_AS_PATH: - if (v1.type != T_PATH) - runtime( "Setting path attribute to non-path value" ); - 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, code); - u32 data = e ? e->u.data : 0; - - if (v1.val.i) - l->attrs[0].u.data = data | BITFIELD_MASK(what); - else - l->attrs[0].u.data = data & ~BITFIELD_MASK(what);; - } - 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; - case EAF_TYPE_UNDEF: - if (v1.type != T_VOID) - runtime( "Setting void attribute to non-void value" ); - l->attrs[0].u.data = 0; - break; - default: bug("Unknown type in e,S"); - } - - f_rta_cow(fs); - l->next = *fs->eattrs; - *fs->eattrs = l; - } - break; - case FI_PREF_GET: - ACCESS_RTE; - res.type = T_INT; - res.val.i = (*fs->rte)->pref; - break; - case FI_PREF_SET: - ACCESS_RTE; - ARG(1,T_INT); - if (v1.val.i > 0xFFFF) - runtime( "Setting preference value out of bounds" ); - f_rte_cow(fs); - (*fs->rte)->pref = v1.val.i; - break; - case FI_LENGTH: /* Get length of */ - ARG_ANY(1); - res.type = T_INT; - switch(v1.type) { - case T_NET: res.val.i = net_pxlen(v1.val.net); break; - case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; - case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break; - case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break; - case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break; - default: runtime( "Prefix, path, clist or eclist expected" ); - } - break; - case FI_SADR_SRC: /* Get SADR 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 *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); - net_fill_ip6(src, net->src_prefix, net->src_pxlen); - - res.type = T_NET; - res.val.net = src; - } - break; - case FI_ROA_MAXLEN: /* Get ROA max prefix length */ - ARG(1, T_NET); - if (!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 FI_ROA_ASN: /* Get ROA ASN */ - ARG(1, T_NET); - if (!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 FI_IP: /* Convert prefix to ... */ - ARG(1, T_NET); - res.type = T_IP; - res.val.ip = net_prefix(v1.val.net); - break; - case FI_ROUTE_DISTINGUISHER: - 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 */ - ARG(1, T_PATH); - - as = 0; - as_path_get_first(v1.val.ad, &as); - res.type = T_INT; - res.val.i = as; - break; - case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */ - ARG(1, T_PATH); - - as = 0; - as_path_get_last(v1.val.ad, &as); - res.type = T_INT; - res.val.i = as; - break; - case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */ - ARG(1, T_PATH); - - res.type = T_INT; - res.val.i = as_path_get_last_nonaggregated(v1.val.ad); - break; - case FI_RETURN: - 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 */ - ARG_ANY(1); - res = interpret(fs, what->a2.p); - if (res.type == T_RETURN) - return res; - res.type &= ~T_RETURN; - break; - case FI_CLEAR_LOCAL_VARS: /* Clear local variables */ - for (sym = what->a1.p; sym != NULL; sym = sym->aux2) - ((struct f_val *) sym->def)->type = T_VOID; - break; - case FI_SWITCH: - ARG_ANY(1); - { - struct f_tree *t = find_tree(what->a2.p, v1); - if (!t) { - v1.type = T_VOID; - t = find_tree(what->a2.p, v1); - if (!t) { - debug( "No else statement?\n"); - break; - } - } - /* It is actually possible to have t->data NULL */ - - INTERPRET(res, t->data); - } - break; - case FI_IP_MASK: /* IP.MASK(val) */ - ARG(1, T_IP); - ARG(2, T_INT); - - 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 FI_EMPTY: /* Create empty attribute */ - res.type = what->aux; - res.val.ad = adata_empty(fs->pool, 0); - break; - case FI_PATH_PREPEND: /* Path prepend */ - ARG(1, T_PATH); - ARG(2, T_INT); - - res.type = T_PATH; - res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); - break; - - case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */ - ARG_ANY(1); - ARG_ANY(2); - if (v1.type == T_PATH) - { - struct f_tree *set = NULL; - u32 key = 0; - int pos; - - if (v2.type == T_INT) - key = v2.val.i; - else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT)) - set = v2.val.t; - else - runtime("Can't delete non-integer (set)"); - - switch (what->aux) - { - case 'a': runtime("Can't add to path"); - case 'd': pos = 0; break; - case 'f': pos = 1; break; - default: bug("unknown Ca operation"); - } - - if (pos && !set) - runtime("Can't filter integer"); - - res.type = T_PATH; - res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos); - } - else if (v1.type == T_CLIST) - { - /* Community (or cluster) list */ - struct f_val dummy; - int arg_set = 0; - uint n = 0; - - if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) - n = v2.val.i; - /* IP->Quad implicit conversion */ - else if (val_is_ip4(v2)) - n = ipa_to_u32(v2.val.ip); - else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy)) - arg_set = 1; - else if (v2.type == T_CLIST) - arg_set = 2; - else - runtime("Can't add/delete non-pair"); - - res.type = T_CLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = int_set_add(fs->pool, v1.val.ad, n); - else - res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = int_set_del(fs->pool, v1.val.ad, n); - else - res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter pair"); - res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } - } - else if (v1.type == T_ECLIST) - { - /* Extended community list */ - int arg_set = 0; - - /* v2.val is either EC or EC-set */ - if ((v2.type == T_SET) && eclist_set_type(v2.val.t)) - arg_set = 1; - else if (v2.type == T_ECLIST) - arg_set = 2; - else if (v2.type != T_EC) - runtime("Can't add/delete non-ec"); - - res.type = T_ECLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec); - else - res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec); - else - res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter ec"); - res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } - } - else if (v1.type == T_LCLIST) - { - /* Large community list */ - int arg_set = 0; - - /* v2.val is either LC or LC-set */ - if ((v2.type == T_SET) && lclist_set_type(v2.val.t)) - arg_set = 1; - else if (v2.type == T_LCLIST) - arg_set = 2; - else if (v2.type != T_LC) - runtime("Can't add/delete non-lc"); - - res.type = T_LCLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc); - else - res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc); - else - res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter lc"); - res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } - } - else - runtime("Can't add/delete to non-[e|l]clist"); - - break; - - case FI_ROA_CHECK: /* ROA Check */ - if (what->arg1) - { - ARG(1, T_NET); - ARG(2, T_INT); - - as = v2.val.i; - } - else - { - ACCESS_RTE; - ACCESS_EATTRS; - v1.val.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"); - - as_path_get_last(e->u.ptr, &as); - } - - 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; - - 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 FI_FORMAT: /* Format */ - ARG_ANY(1); - - res.type = T_STRING; - res.val.s = val_format_str(fs, v1); - break; - - case FI_ASSERT: /* Birdtest Assert */ - ARG(1, T_BOOL); - - res.type = v1.type; - res.val = v1.val; - - CALL(bt_assert_hook, res.val.i, what); - break; - - default: - bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +#include "filter/f-inst.c" #undef runtime #undef ARG_ANY From 7afa1438866fa94454ba133608b6877171f71d37 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 13:51:11 +0100 Subject: [PATCH 06/88] Filter refactoring: Passing the resulting struct f_val as a pointer. This also drops the multiplexing of errors with the f_val itself together with the T_RETURN f_val type flag. --- conf/confbase.Y | 3 +-- filter/config.Y | 2 +- filter/f-inst.c | 26 ++++++++++------------ filter/filter.c | 52 ++++++++++++++++++++++++-------------------- filter/filter.h | 25 +++++++++++---------- filter/filter_test.c | 8 +++---- nest/cmds.c | 5 ++--- 7 files changed, 60 insertions(+), 61 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index 3fd034db..3d573e10 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -124,8 +124,7 @@ conf: definition ; definition: DEFINE SYM '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); - *val = f_eval($4, cfg_mem); - if (val->type == T_RETURN) cf_error("Runtime error"); + if (f_eval($4, cfg_mem, val) > F_RETURN) cf_error("Runtime error"); cf_define_symbol($2, SYM_CONSTANT | val->type, val); } ; diff --git a/filter/config.Y b/filter/config.Y index c1e74531..200c1f41 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -653,7 +653,7 @@ set_atom: | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - $$ = f_eval($2, cfg_mem); + if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } | SYM { diff --git a/filter/f-inst.c b/filter/f-inst.c index 24908442..814e026d 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -121,15 +121,15 @@ while (tt) { *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); if (tt->kind == PM_ASN_EXPR) { - struct f_val res; - INTERPRET(res, (struct f_inst *) tt->val); + struct f_val xres; + INTERPRET(xres, (struct f_inst *) tt->val); (*vv)->kind = PM_ASN; - if (res.type != T_INT) { + if (xres.type != T_INT) { runtime( "Error resolving path mask template: value not an integer" ); - return (struct f_val) { .type = T_VOID }; + return F_ERROR; } - (*vv)->val = res.val.i; + (*vv)->val = xres.val.i; } else { **vv = *tt; } @@ -280,9 +280,7 @@ /* 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 */ - res.type = T_RETURN; - res.val.i = what->a2.i; - return res; /* We have to return now, no more processing. */ + return what->a2.i; /* We have to return now, no more processing. */ case F_NONL: case F_NOP: break; @@ -658,14 +656,12 @@ case FI_RETURN: 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 */ + return F_RETURN; + case FI_CALL: ARG_ANY(1); - res = interpret(fs, what->a2.p); - if (res.type == T_RETURN) - return res; - res.type &= ~T_RETURN; + fret = interpret(fs, what->a2.p, &res); + if (fret > F_RETURN) + return fret; break; case FI_CLEAR_LOCAL_VARS: /* Clear local variables */ for (sym = what->a1.p; sym != NULL; sym = sym->aux2) diff --git a/filter/filter.c b/filter/filter.c index 794e35e8..1e6fc003 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -615,24 +615,27 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; * &f_val structures are copied around, so there are no problems with * memory managment. */ -static struct f_val -interpret(struct filter_state *fs, struct f_inst *what) +static enum filter_return +interpret(struct filter_state *fs, struct f_inst *what, struct f_val *resp) { struct symbol *sym; - struct f_val v1, v2, v3, res = { .type = T_VOID }, *vp; + struct f_val v1, v2, v3, *vp; unsigned u1, u2; + enum filter_return fret; int i; u32 as; + *resp = (struct f_val) { .type = T_VOID }; + for ( ; what; what = what->next) { - res.type = T_VOID; +#define res (*resp) + res = (struct f_val) { .type = T_VOID }; switch(what->fi_code) { + #define runtime(fmt, ...) do { \ if (!(fs->flags & FF_SILENT)) \ log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ - res.type = T_RETURN; \ - res.val.i = F_ERROR; \ - return res; \ + return F_ERROR; \ } while(0) #define ARG_ANY(n) INTERPRET(v##n, what->a##n.p) @@ -643,9 +646,9 @@ interpret(struct filter_state *fs, struct f_inst *what) n, f_instruction_name(what->fi_code), t, v##n.type); #define INTERPRET(val, what_) \ - val = interpret(fs, what_); \ - if (val.type & T_RETURN) \ - return val; + fret = interpret(fs, what_, &(val)); \ + if (fret >= F_RETURN) \ + return fret; #define ACCESS_RTE \ do { if (!fs->rte) runtime("No route to access"); } while (0) @@ -657,6 +660,7 @@ interpret(struct filter_state *fs, struct f_inst *what) #include "filter/f-inst.c" +#undef res #undef runtime #undef ARG_ANY #undef ARG @@ -664,7 +668,7 @@ interpret(struct filter_state *fs, struct f_inst *what) #undef ACCESS_RTE #undef ACCESS_EATTRS }} - return res; + return F_NOP; } @@ -837,7 +841,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) * (and cached rta of read-only source rte is intact), if rte is * modified in place, old cached rta is possibly freed. */ -int +enum filter_return f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) { if (filter == FILTER_ACCEPT) @@ -857,7 +861,8 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla LOG_BUFFER_INIT(fs.buf); - struct f_val res = interpret(&fs, filter->root); + struct f_val res; + enum filter_return fret = interpret(&fs, filter->root, &res); if (fs.old_rta) { /* @@ -879,18 +884,18 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla } - if (res.type != T_RETURN) { + if (fret < F_ACCEPT) { if (!(fs.flags & FF_SILENT)) log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); return F_ERROR; } DBG( "done (%u)\n", res.val.i ); - return res.val.i; + return fret; } /* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */ -struct f_val +enum filter_return f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) { @@ -902,13 +907,12 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) LOG_BUFFER_INIT(fs.buf); /* Note that in this function we assume that rte->attrs is private / uncached */ - struct f_val res = interpret(&fs, expr); - - return res; + struct f_val res; + return interpret(&fs, expr, &res); } -struct f_val -f_eval(struct f_inst *expr, struct linpool *tmp_pool) +enum filter_return +f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres) { struct filter_state fs = { .pool = tmp_pool, @@ -916,14 +920,16 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool) LOG_BUFFER_INIT(fs.buf); - return interpret(&fs, expr); + return interpret(&fs, expr, pres); } uint f_eval_int(struct f_inst *expr) { /* Called independently in parse-time to eval expressions */ - struct f_val res = f_eval(expr, cfg_mem); + struct f_val res; + if (f_eval(expr, cfg_mem, &res) > F_RETURN) + cf_error("Runtime error while evaluating expression"); if (res.type != T_INT) cf_error("Integer expression expected"); diff --git a/filter/filter.h b/filter/filter.h index a8c33287..8728f679 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -175,9 +175,19 @@ void trie_format(struct f_trie *t, buffer *buf); struct ea_list; struct rte; -int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); -struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); -struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); +enum filter_return { + F_NOP = 0, + F_NONL, + F_RETURN, + F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */ + F_REJECT, + F_ERROR, + F_QUITBIRD, +}; + +enum filter_return f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); +enum filter_return f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); +enum filter_return f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres); uint f_eval_int(struct f_inst *expr); char *filter_name(struct filter *filter); @@ -190,14 +200,6 @@ int val_same(struct f_val v1, struct f_val v2); void val_format(struct f_val v, buffer *buf); - -#define F_NOP 0 -#define F_NONL 1 -#define F_ACCEPT 2 /* Need to preserve ordering: accepts < rejects! */ -#define F_REJECT 3 -#define F_ERROR 4 -#define F_QUITBIRD 5 - #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) #define FILTER_UNDEF ((void *) 2) /* Used in BGP */ @@ -246,7 +248,6 @@ void val_format(struct f_val v, buffer *buf); #define T_LCLIST 0x29 /* Large community list */ #define T_RD 0x2a /* Route distinguisher for VPN addresses */ -#define T_RETURN 0x40 #define T_SET 0x80 #define T_PREFIX_SET 0x81 diff --git a/filter/filter_test.c b/filter/filter_test.c index be7fd521..b319225b 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -44,13 +44,11 @@ run_function(const void *parsed_fn_def) struct f_inst *f = (struct f_inst *) parsed_fn_def; linpool *tmp = lp_new_default(&root_pool); - struct f_val res = f_eval(f, tmp); + struct f_val res; + enum filter_return fret = f_eval(f, tmp, &res); rfree(tmp); - if (res.type == T_RETURN && res.val.i >= F_REJECT) - return 0; - - return 1; + return (fret < F_REJECT); } static void diff --git a/nest/cmds.c b/nest/cmds.c index ca601ef2..0c89d20f 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -97,9 +97,8 @@ cmd_show_memory(void) void cmd_eval(struct f_inst *expr) { - struct f_val v = f_eval(expr, this_cli->parser_pool); - - if (v.type == T_RETURN) + struct f_val v; + if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN) { cli_msg(8008, "runtime error"); return; From fc8df41ec6cd5e6e3d53036a97dc7219dbbade5e Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 17 Dec 2018 15:00:01 +0100 Subject: [PATCH 07/88] Filter refactoring: The values are now saved on a custom stack. This shall help with performance. --- filter/f-inst.c | 13 ++++----- filter/filter.c | 70 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 814e026d..41cace61 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -121,15 +121,14 @@ while (tt) { *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); if (tt->kind == PM_ASN_EXPR) { - struct f_val xres; - INTERPRET(xres, (struct f_inst *) tt->val); + INTERPRET((struct f_inst *) tt->val, 0); (*vv)->kind = PM_ASN; - if (xres.type != T_INT) { + if (res.type != T_INT) { runtime( "Error resolving path mask template: value not an integer" ); return F_ERROR; } - (*vv)->val = xres.val.i; + (*vv)->val = res.val.i; } else { **vv = *tt; } @@ -659,7 +658,7 @@ return F_RETURN; case FI_CALL: ARG_ANY(1); - fret = interpret(fs, what->a2.p, &res); + fret = interpret(fs, what->a2.p); if (fret > F_RETURN) return fret; break; @@ -681,7 +680,9 @@ } /* It is actually possible to have t->data NULL */ - INTERPRET(res, t->data); + fret = interpret(fs, t->data); + if (fret >= F_RETURN) + return fret; } break; case FI_IP_MASK: /* IP.MASK(val) */ diff --git a/filter/filter.c b/filter/filter.c index 1e6fc003..62804aec 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -50,6 +50,15 @@ #define CMP_ERROR 999 +#define FILTER_STACK_DEPTH 16384 + +/* Filter interpreter stack. Make this thread local after going parallel. */ +struct filter_stack { + struct f_val val; +}; + +static struct filter_stack filter_stack[FILTER_STACK_DEPTH]; + /* Internal filter state, to be allocated on stack when executing filters */ struct filter_state { struct rte **rte; @@ -57,6 +66,8 @@ struct filter_state { struct ea_list **eattrs; struct linpool *pool; struct buffer buf; + struct filter_stack *stack; + int stack_ptr; int flags; }; @@ -611,24 +622,25 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; * are either integers, or pointers to instruction trees. Common * instructions like +, that have two expressions as arguments use * TWOARGS macro to get both of them evaluated. - * - * &f_val structures are copied around, so there are no problems with - * memory managment. */ static enum filter_return -interpret(struct filter_state *fs, struct f_inst *what, struct f_val *resp) +interpret(struct filter_state *fs, struct f_inst *what) { struct symbol *sym; - struct f_val v1, v2, v3, *vp; + struct f_val *vp; unsigned u1, u2; enum filter_return fret; int i; u32 as; - *resp = (struct f_val) { .type = T_VOID }; +#define res fs->stack[fs->stack_ptr].val +#define v1 fs->stack[fs->stack_ptr + 1].val +#define v2 fs->stack[fs->stack_ptr + 2].val +#define v3 fs->stack[fs->stack_ptr + 3].val + + res = (struct f_val) { .type = T_VOID }; for ( ; what; what = what->next) { -#define res (*resp) res = (struct f_val) { .type = T_VOID }; switch(what->fi_code) { @@ -638,17 +650,22 @@ interpret(struct filter_state *fs, struct f_inst *what, struct f_val *resp) return F_ERROR; \ } while(0) -#define ARG_ANY(n) INTERPRET(v##n, what->a##n.p) +#define ARG_ANY(n) INTERPRET(what->a##n.p, n) -#define ARG(n,t) ARG_ANY(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 INTERPRET(val, what_) \ - fret = interpret(fs, what_, &(val)); \ - if (fret >= F_RETURN) \ - return fret; +#define INTERPRET(what_, n) do { \ + fs->stack_ptr += n; \ + fret = interpret(fs, what_); \ + fs->stack_ptr -= n; \ + if (fret == F_RETURN) \ + bug("This shall not happen"); \ + if (fret > F_RETURN) \ + return fret; \ +} while (0) #define ACCESS_RTE \ do { if (!fs->rte) runtime("No route to access"); } while (0) @@ -857,12 +874,12 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla .rte = rte, .pool = tmp_pool, .flags = flags, + .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); - struct f_val res; - enum filter_return fret = interpret(&fs, filter->root, &res); + enum filter_return fret = interpret(&fs, filter->root); if (fs.old_rta) { /* @@ -902,13 +919,13 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) struct filter_state fs = { .rte = rte, .pool = tmp_pool, + .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); /* Note that in this function we assume that rte->attrs is private / uncached */ - struct f_val res; - return interpret(&fs, expr, &res); + return interpret(&fs, expr); } enum filter_return @@ -916,25 +933,34 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres) { struct filter_state fs = { .pool = tmp_pool, + .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); - return interpret(&fs, expr, pres); + enum filter_return fret = interpret(&fs, expr); + *pres = filter_stack[0].val; + return fret; } uint f_eval_int(struct f_inst *expr) { /* Called independently in parse-time to eval expressions */ - struct f_val res; - if (f_eval(expr, cfg_mem, &res) > F_RETURN) + struct filter_state fs = { + .pool = cfg_mem, + .stack = filter_stack, + }; + + LOG_BUFFER_INIT(fs.buf); + + if (interpret(&fs, expr) > F_RETURN) cf_error("Runtime error while evaluating expression"); - if (res.type != T_INT) + if (filter_stack[0].val.type != T_INT) cf_error("Integer expression expected"); - return res.val.i; + return filter_stack[0].val.val.i; } /** From a8740d6c09547dd9fe445b3deb5238305c0a5959 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 18 Dec 2018 17:10:05 +0100 Subject: [PATCH 08/88] Filter refactoring: indentation fix --- filter/filter.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 62804aec..b15ede8a 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -641,37 +641,37 @@ interpret(struct filter_state *fs, struct f_inst *what) res = (struct f_val) { .type = T_VOID }; for ( ; what; what = what->next) { - res = (struct f_val) { .type = T_VOID }; - switch(what->fi_code) { + res = (struct f_val) { .type = T_VOID }; + switch (what->fi_code) { #define runtime(fmt, ...) do { \ - if (!(fs->flags & FF_SILENT)) \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ - return F_ERROR; \ - } while(0) + if (!(fs->flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + return F_ERROR; \ +} while(0) #define ARG_ANY(n) INTERPRET(what->a##n.p, 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 INTERPRET(what_, n) do { \ - fs->stack_ptr += n; \ - fret = interpret(fs, what_); \ - fs->stack_ptr -= n; \ - if (fret == F_RETURN) \ - bug("This shall not happen"); \ - if (fret > F_RETURN) \ - return fret; \ +#define ARG(n,t) do { \ + 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); \ } while (0) -#define ACCESS_RTE \ - do { if (!fs->rte) runtime("No route to access"); } while (0) +#define INTERPRET(what_, n) do { \ + fs->stack_ptr += n; \ + fret = interpret(fs, what_); \ + fs->stack_ptr -= n; \ + if (fret == F_RETURN) \ + bug("This shall not happen"); \ + if (fret > F_RETURN) \ + return fret; \ +} while (0) -#define ACCESS_EATTRS \ - do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) +#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) + +#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) #define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a2.i)) @@ -684,7 +684,8 @@ interpret(struct filter_state *fs, struct f_inst *what) #undef INTERPRET #undef ACCESS_RTE #undef ACCESS_EATTRS - }} + } + } return F_NOP; } From c577493908a9cda9008cc4043d0473b69fb2da66 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 14:05:32 +0100 Subject: [PATCH 09/88] Filter refactoring: Expanded the short instructions with common code. This will make the further changes more straightforward. --- filter/f-inst.c | 60 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 41cace61..4041a804 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -36,11 +36,18 @@ res.val.i = v1.val.i / v2.val.i; break; case FI_AND: + ARG(1,T_BOOL); + if (!v1.val.i) { + res = v1; + } else { + ARG(2,T_BOOL); + res = v2; + } + break; case FI_OR: ARG(1,T_BOOL); - if (v1.val.i == (what->fi_code == FI_OR)) { - res.type = T_BOOL; - res.val.i = v1.val.i; + if (v1.val.i) { + res = v1; } else { ARG(2,T_BOOL); res = v2; @@ -142,28 +149,39 @@ /* Relational operators */ -#define COMPARE(x) \ - ARG_ANY(1); \ - ARG_ANY(2); \ - i = val_compare(v1, v2); \ - if (i==CMP_ERROR) \ - runtime( "Can't compare values of incompatible types" ); \ - res.type = T_BOOL; \ - res.val.i = (x); \ + case FI_NEQ: + ARG_ANY(1); + ARG_ANY(2); + res.type = T_BOOL; + res.val.i = !val_same(v1, v2); break; -#define SAME(x) \ - ARG_ANY(1); \ - ARG_ANY(2); \ - i = val_same(v1, v2); \ - res.type = T_BOOL; \ - res.val.i = (x); \ + case FI_EQ: + ARG_ANY(1); + ARG_ANY(2); + res.type = T_BOOL; + res.val.i = val_same(v1, v2); break; - case FI_NEQ: SAME(!i); - case FI_EQ: SAME(i); - case FI_LT: COMPARE(i==-1); - case FI_LTE: COMPARE(i!=1); + case FI_LT: + ARG_ANY(1); + ARG_ANY(2); + i = val_compare(v1, v2); + if (i==CMP_ERROR) + runtime( "Can't compare values of incompatible types" ); + res.type = T_BOOL; + res.val.i = (i == -1); + break; + + case FI_LTE: + ARG_ANY(1); + ARG_ANY(2); + i = val_compare(v1, v2); + if (i==CMP_ERROR) + runtime( "Can't compare values of incompatible types" ); + res.type = T_BOOL; + res.val.i = (i != 1); + break; case FI_NOT: ARG(1,T_BOOL); From 8e8b1fe48cfcb92d54e15df5198e8cef9bc3dd8e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 14:29:47 +0100 Subject: [PATCH 10/88] Filter refactoring: Some instructions eat up excessively much space. --- filter/f-inst.c | 59 ++++++++++++++++++------------------------------- filter/filter.c | 14 +++++++----- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 4041a804..cee5b8e7 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -11,47 +11,35 @@ /* Binary operators */ case FI_ADD: - ARG(1,T_INT); - ARG(2,T_INT); - res.type = T_INT; - res.val.i = v1.val.i + v2.val.i; + ARG_T(1,0,T_INT); + ARG_T(2,1,T_INT); + res.val.i += v1.val.i; break; case FI_SUBTRACT: - ARG(1,T_INT); - ARG(2,T_INT); - res.type = T_INT; - res.val.i = v1.val.i - v2.val.i; + ARG_T(1,0,T_INT); + ARG_T(2,1,T_INT); + res.val.i -= v1.val.i; break; case FI_MULTIPLY: - ARG(1,T_INT); - ARG(2,T_INT); - res.type = T_INT; - res.val.i = v1.val.i * v2.val.i; + ARG_T(1,0,T_INT); + ARG_T(2,1,T_INT); + res.val.i *= v1.val.i; break; case FI_DIVIDE: - 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; + ARG_T(1,0,T_INT); + ARG_T(2,1,T_INT); + if (v1.val.i == 0) runtime( "Mother told me not to divide by 0" ); + res.val.i /= v1.val.i; break; case FI_AND: - ARG(1,T_BOOL); - if (!v1.val.i) { - res = v1; - } else { - ARG(2,T_BOOL); - res = v2; - } + ARG_T(1,0,T_BOOL); + if (res.val.i) + ARG_T(2,0,T_BOOL); break; case FI_OR: - ARG(1,T_BOOL); - if (v1.val.i) { - res = v1; - } else { - ARG(2,T_BOOL); - res = v2; - } + ARG_T(1,0,T_BOOL); + if (!res.val.i) + ARG_T(2,0,T_BOOL); break; case FI_PAIR_CONSTRUCT: ARG(1,T_INT); @@ -184,8 +172,7 @@ break; case FI_NOT: - ARG(1,T_BOOL); - res = v1; + ARG_T(1,0,T_BOOL); res.val.i = !res.val.i; break; @@ -642,7 +629,6 @@ break; case FI_ROUTE_DISTINGUISHER: ARG(1, T_NET); - res.type = T_IP; if (!net_is_vpn(v1.val.net)) runtime( "VPN address expected" ); res.type = T_RD; @@ -671,11 +657,10 @@ res.val.i = as_path_get_last_nonaggregated(v1.val.ad); break; case FI_RETURN: - ARG_ANY(1); - res = v1; + ARG_ANY_T(1,0); return F_RETURN; case FI_CALL: - ARG_ANY(1); + ARG_ANY_T(1,0); fret = interpret(fs, what->a2.p); if (fret > F_RETURN) return fret; diff --git a/filter/filter.c b/filter/filter.c index b15ede8a..a1bb7415 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -634,6 +634,7 @@ interpret(struct filter_state *fs, struct f_inst *what) u32 as; #define res fs->stack[fs->stack_ptr].val +#define v0 res #define v1 fs->stack[fs->stack_ptr + 1].val #define v2 fs->stack[fs->stack_ptr + 2].val #define v3 fs->stack[fs->stack_ptr + 3].val @@ -650,15 +651,18 @@ interpret(struct filter_state *fs, struct f_inst *what) return F_ERROR; \ } while(0) -#define ARG_ANY(n) INTERPRET(what->a##n.p, n) +#define ARG_ANY_T(n, tt) INTERPRET(what->a##n.p, tt) +#define ARG_ANY(n) ARG_ANY_T(n, n) -#define ARG(n,t) do { \ - ARG_ANY(n); \ - if (v##n.type != t) \ +#define ARG_T(n,tt,t) do { \ + ARG_ANY_T(n,tt); \ + if (v##tt.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); \ + n, f_instruction_name(what->fi_code), t, v##tt.type); \ } while (0) +#define ARG(n,t) ARG_T(n,n,t) + #define INTERPRET(what_, n) do { \ fs->stack_ptr += n; \ fret = interpret(fs, what_); \ From 224b77d4f786ea09bb2632476a89f0976baafd64 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 14:34:35 +0100 Subject: [PATCH 11/88] Filter refactoring: Converted condition to three-args instruction --- filter/config.Y | 12 +++++------- filter/f-inst.c | 14 ++++++-------- filter/filter.c | 2 +- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 200c1f41..05c6f899 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -559,7 +559,7 @@ filter: where_filter: WHERE term { - /* Construct 'IF term THEN ACCEPT; REJECT;' */ + /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ struct filter *f = cfg_alloc(sizeof(struct filter)); struct f_inst *i, *acc, *rej; acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ @@ -571,7 +571,7 @@ where_filter: i = f_new_inst(FI_CONDITION); /* IF */ i->a1.p = $2; i->a2.p = acc; - i->next = rej; + i->a3.p = rej; f->name = NULL; f->root = i; $$ = f; @@ -1005,12 +1005,10 @@ cmd: $$->a2.p = $4; } | IF term THEN block ELSE block { - struct f_inst *i = f_new_inst(FI_CONDITION); - i->a1.p = $2; - i->a2.p = $4; $$ = f_new_inst(FI_CONDITION); - $$->a1.p = i; - $$->a2.p = $6; + $$->a1.p = $2; + $$->a2.p = $4; + $$->a3.p = $6; } | SYM '=' term ';' { DBG( "Ook, we'll set value\n" ); diff --git a/filter/f-inst.c b/filter/f-inst.c index cee5b8e7..fc960198 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -259,14 +259,12 @@ ARG_ANY(1); val_format(v1, &fs->buf); break; - case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */ - ARG(1, T_BOOL); - if (v1.val.i) { - ARG_ANY(2); - res.val.i = 0; - } else - res.val.i = 1; - res.type = T_BOOL; + case FI_CONDITION: + ARG_T(1, 0, T_BOOL); + if (res.val.i) + ARG_ANY_T(2,0); + else + ARG_ANY_T(3,0); break; case FI_NOP: debug( "No operation\n" ); diff --git a/filter/filter.c b/filter/filter.c index a1bb7415..3b310257 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -793,7 +793,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) return 0; break; case FI_PRINT: case FI_LENGTH: ONEARG; break; - case FI_CONDITION: TWOARGS; break; + case FI_CONDITION: THREEARGS; break; case FI_NOP: case FI_EMPTY: break; case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break; case FI_PREF_GET: From 7f0ac73724f7383a2bcc229910414d339dbd2434 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 14:55:40 +0100 Subject: [PATCH 12/88] Filter refactoring: Changed arguments from separate unions to an array --- filter/config.Y | 210 +++++++++++++++++++++---------------------- filter/f-inst.c | 40 ++++----- filter/f-util.c | 12 +-- filter/filter.c | 34 +++---- filter/filter.h | 15 +--- filter/filter_test.c | 2 +- 6 files changed, 153 insertions(+), 160 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 05c6f899..20a19075 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -178,7 +178,7 @@ f_generate_empty(struct f_dynamic_attr dyn) } struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn); - s->a1.p = e; + s->a[0].p = e; return s; } @@ -192,17 +192,17 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2) if ((t1->aux != T_INT) || (t2->aux != T_INT)) cf_error( "Can't operate with value of non-integer type in pair constructor"); - check_u16(t1->a2.i); - check_u16(t2->a2.i); + check_u16(t1->a[1].i); + check_u16(t2->a[1].i); rv = f_new_inst(FI_CONSTANT); rv->aux = T_PAIR; - rv->a2.i = pair(t1->a2.i, t2->a2.i); + rv->a[1].i = pair(t1->a[1].i, t2->a[1].i); } else { rv = f_new_inst(FI_PAIR_CONSTRUCT); - rv->a1.p = t1; - rv->a2.p = t2; + rv->a[0].p = t1; + rv->a[1].p = t2; } return rv; @@ -219,10 +219,10 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) c1 = 1; if (tk->aux == T_INT) { - ipv4_used = 0; key = tk->a2.i; + ipv4_used = 0; key = tk->a[1].i; } else if (tk->aux == T_QUAD) { - ipv4_used = 1; key = tk->a2.i; + ipv4_used = 1; key = tk->a[1].i; } else cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); @@ -231,7 +231,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) /* IP->Quad implicit conversion */ else if (tk->fi_code == FI_CONSTANT_INDIRECT) { c1 = 1; - struct f_val *val = tk->a1.p; + struct f_val *val = tk->a[0].p; if (val->type == T_INT) { ipv4_used = 0; key = val->val.i; @@ -250,7 +250,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) if (tv->aux != T_INT) cf_error("Can't operate with value of non-integer type in EC constructor"); c2 = 1; - val2 = tv->a2.i; + val2 = tv->a[1].i; } if (c1 && c2) { @@ -273,15 +273,15 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) NEW_F_VAL; rv = f_new_inst(FI_CONSTANT_INDIRECT); - rv->a1.p = val; + rv->a[0].p = val; val->type = T_EC; val->val.ec = ec; } else { rv = f_new_inst(FI_EC_CONSTRUCT); rv->aux = kind; - rv->a1.p = tk; - rv->a2.p = tv; + rv->a[0].p = tk; + rv->a[1].p = tv; } return rv; @@ -299,16 +299,16 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) rv = f_new_inst(FI_CONSTANT_INDIRECT); NEW_F_VAL; - rv->a1.p = val; + rv->a[0].p = val; val->type = T_LC; - val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i }; + val->val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i }; } else { rv = f_new_inst(FI_LC_CONSTRUCT); - rv->a1.p = t1; - rv->a2.p = t2; - rv->a3.p = t3; + rv->a[0].p = t1; + rv->a[1].p = t2; + rv->a[2].p = t3; } return rv; @@ -320,7 +320,7 @@ f_generate_path_mask(struct f_path_mask *t) for (struct f_path_mask *tt = t; tt; tt = tt->next) { if (tt->kind == PM_ASN_EXPR) { struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT); - mrv->a1.p = t; + mrv->a[0].p = t; return mrv; } } @@ -330,7 +330,7 @@ f_generate_path_mask(struct f_path_mask *t) val->val.path_mask = t; struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT); - rv->a1.p = val; + rv->a[0].p = val; return rv; } @@ -385,16 +385,16 @@ 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; + i->a[0].p = expr; if (end >= start) { - i->a2.p = assert_copy_expr(start, end - start + 1); + i->a[1].p = assert_copy_expr(start, end - start + 1); } else { /* this is a break of lexer buffer */ - i->a2.p = "???"; + i->a[1].p = "???"; } return i; @@ -563,15 +563,15 @@ where_filter: struct filter *f = cfg_alloc(sizeof(struct filter)); struct f_inst *i, *acc, *rej; acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ - acc->a1.p = NULL; - acc->a2.i = F_ACCEPT; + acc->a[0].p = NULL; + acc->a[1].i = F_ACCEPT; rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */ - rej->a1.p = NULL; - rej->a2.i = F_REJECT; + rej->a[0].p = NULL; + rej->a[1].i = F_REJECT; i = f_new_inst(FI_CONDITION); /* IF */ - i->a1.p = $2; - i->a2.p = acc; - i->a3.p = rej; + i->a[0].p = $2; + i->a[1].p = acc; + i->a[2].p = rej; f->name = NULL; f->root = i; $$ = f; @@ -588,7 +588,7 @@ function_body: if ($1) { /* Prepend instruction to clear local variables */ $$ = f_new_inst(FI_CLEAR_LOCAL_VARS); - $$->a1.p = $1; + $$->a[0].p = $1; $$->next = $3; } else $$ = $3; @@ -771,7 +771,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } } ; -/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */ +/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $3; } */ bgp_path_expr: symbol { $$ = $1; } @@ -792,16 +792,16 @@ bgp_path_tail: ; constant: - 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; } - | 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; } + NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $1; } + | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 1; } + | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 0; } + | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a[1].p = $1; } + | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a[0].p = val; *val = $1; } + | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a[0].p = val; } + | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a[0].p = val; } + | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a[1].p = build_tree($2); DBG( "ook\n" ); } + | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a[1].p = $2; } + | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a[1].i = $1 & 0xffff; } ; constructor: @@ -823,14 +823,14 @@ function_call: cf_error("You can't call something which is not a function. Really."); DBG("You are calling function %s\n", $1->name); $$ = f_new_inst(FI_CALL); - $$->a1.p = inst; - $$->a2.p = $1->def; + $$->a[0].p = inst; + $$->a[1].p = $1->def; sym = $1->aux2; while (sym || inst) { if (!sym || !inst) cf_error("Wrong number of arguments for function %s.", $1->name); DBG( "You should pass parameter called %s\n", sym->name); - inst->a1.p = sym; + inst->a[0].p = sym; sym = sym->aux2; inst = inst->next; } @@ -846,8 +846,8 @@ symbol: case SYM_VARIABLE_RANGE: $$ = f_new_inst(FI_VARIABLE); cv_common: - $$->a1.p = $1->def; - $$->a2.p = $1->name; + $$->a[0].p = $1->def; + $$->a[1].p = $1->name; break; case SYM_ATTRIBUTE: $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); @@ -871,22 +871,22 @@ static_attr: term: '(' term ')' { $$ = $2; } - | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; } - | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; } - | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; } - | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; } - | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; } - | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; } - | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; } - | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; } - | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; } - | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; } - | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; } - | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; } - | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; } - | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; } - | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; } - | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; } + | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; } + | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; } + | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; } + | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; } + | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; } + | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; } + | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; } + | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; } + | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; } + | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; } + | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; } | symbol { $$ = $1; } | constant { $$ = $1; } @@ -898,18 +898,18 @@ term: | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); } - | 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 '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->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; } + | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; } + | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; } + | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; } + | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; } + | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; } + | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; } + | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; } + | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; } + | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; } + | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; } + | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; } + | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; } /* Communities */ /* This causes one shift/reduce conflict @@ -923,15 +923,15 @@ term: | '-' 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'; } + | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; } + | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; } + | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; } + | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; } | 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(FI_FORMAT); $$->a1.p = $3; } + | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; } /* | term '.' LEN { $$->code = P('P','l'); } */ @@ -943,14 +943,14 @@ term: cf_error("You can't call something which is not a function. Really."); DBG("You are calling function %s\n", $1->name); $$ = f_new_inst(FI_CALL); - $$->a1.p = inst; - $$->a2.p = $1->def; + $$->a[0].p = inst; + $$->a[1].p = $1->def; sym = $1->aux2; while (sym || inst) { if (!sym || !inst) cf_error("Wrong number of arguments for function %s.", $1->name); DBG( "You should pass parameter called %s\n", sym->name); - inst->a1.p = sym; + inst->a[0].p = sym; sym = sym->aux2; inst = inst->next; } @@ -967,7 +967,7 @@ break_command: ; print_one: - term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; } + term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; } ; print_list: /* EMPTY */ { $$ = NULL; } @@ -982,14 +982,14 @@ print_list: /* EMPTY */ { $$ = NULL; } var_listn: term { $$ = f_new_inst(FI_SET); - $$->a1.p = NULL; - $$->a2.p = $1; + $$->a[0].p = NULL; + $$->a[1].p = $1; $$->next = NULL; } | term ',' var_listn { $$ = f_new_inst(FI_SET); - $$->a1.p = NULL; - $$->a2.p = $1; + $$->a[0].p = NULL; + $$->a[1].p = $1; $$->next = $3; } ; @@ -1001,57 +1001,57 @@ var_list: /* EMPTY */ { $$ = NULL; } cmd: IF term THEN block { $$ = f_new_inst(FI_CONDITION); - $$->a1.p = $2; - $$->a2.p = $4; + $$->a[0].p = $2; + $$->a[1].p = $4; } | IF term THEN block ELSE block { $$ = f_new_inst(FI_CONDITION); - $$->a1.p = $2; - $$->a2.p = $4; - $$->a3.p = $6; + $$->a[0].p = $2; + $$->a[1].p = $4; + $$->a[2].p = $6; } | SYM '=' term ';' { DBG( "Ook, we'll set value\n" ); if ($1->class == SYM_ATTRIBUTE) { $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def)); - $$->a1.p = $3; + $$->a[0].p = $3; } else if (($1->class & ~T_MASK) == SYM_VARIABLE) { $$ = f_new_inst(FI_SET); - $$->a1.p = $1; - $$->a2.p = $3; + $$->a[0].p = $1; + $$->a[1].p = $3; } else cf_error( "Symbol `%s' is read-only.", $1->name ); } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); $$ = f_new_inst(FI_RETURN); - $$->a1.p = $2; + $$->a[0].p = $2; } | rtadot dynamic_attr '=' term ';' { $$ = f_new_inst_da(FI_EA_SET, $2); - $$->a1.p = $4; + $$->a[0].p = $4; } | rtadot static_attr '=' term ';' { $$ = f_new_inst_sa(FI_RTA_SET, $2); - if (!$$->a1.i) + if (!$$->a[0].i) cf_error( "This static attribute is read-only."); - $$->a1.p = $4; + $$->a[0].p = $4; } | PREFERENCE '=' term ';' { $$ = f_new_inst(FI_PREF_SET); - $$->a1.p = $3; + $$->a[0].p = $3; } | UNSET '(' rtadot dynamic_attr ')' ';' { $$ = f_new_inst_da(FI_EA_SET, $4); $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; - $$->a1.p = NULL; + $$->a[0].p = NULL; } - | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; } + | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; } | function_call ';' { $$ = $1; } | CASE term '{' switch_body '}' { $$ = f_new_inst(FI_SWITCH); - $$->a1.p = $2; - $$->a2.p = build_tree( $4 ); + $$->a[0].p = $2; + $$->a[1].p = build_tree( $4 ); } | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } diff --git a/filter/f-inst.c b/filter/f-inst.c index fc960198..a7d381c2 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -111,7 +111,7 @@ case FI_PATHMASK_CONSTRUCT: { - struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin; + struct f_path_mask *tt = what->a[0].p, *vbegin, **vv = &vbegin; while (tt) { *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); @@ -219,10 +219,10 @@ res.val.i = ipa_is_ip4(v1.val.ip); break; - /* Set to indirect value, a1 = variable, a2 = value */ + /* Set to indirect value, a[0] = variable, a[1] = value */ case FI_SET: ARG_ANY(2); - sym = what->a1.p; + sym = what->a[0].p; vp = sym->def; if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) { @@ -238,22 +238,22 @@ *vp = v2; break; - /* some constants have value in a2, some in *a1.p, strange. */ + /* some constants have value in a[1], some in *a[0].p, strange. */ case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */ res.type = what->aux; if (res.type == T_PREFIX_SET) - res.val.ti = what->a2.p; + res.val.ti = what->a[1].p; else if (res.type == T_SET) - res.val.t = what->a2.p; + res.val.t = what->a[1].p; else if (res.type == T_STRING) - res.val.s = what->a2.p; + res.val.s = what->a[1].p; else - res.val.i = what->a2.i; + res.val.i = what->a[1].i; break; case FI_VARIABLE: case FI_CONSTANT_INDIRECT: - res = * ((struct f_val *) what->a1.p); + res = * ((struct f_val *) what->a[0].p); break; case FI_PRINT: ARG_ANY(1); @@ -271,18 +271,18 @@ break; case FI_PRINT_AND_DIE: ARG_ANY(1); - if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && + if ((what->a[1].i == F_NOP || (what->a[1].i != F_NONL && what->a[0].p)) && !(fs->flags & FF_SILENT)) log_commit(*L_INFO, &fs->buf); - switch (what->a2.i) { + switch (what->a[1].i) { case F_QUITBIRD: die( "Filter asked me to die" ); 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 */ - return what->a2.i; /* We have to return now, no more processing. */ + return what->a[1].i; /* We have to return now, no more processing. */ case F_NONL: case F_NOP: break; @@ -296,7 +296,7 @@ struct rta *rta = (*fs->rte)->attrs; res.type = what->aux; - switch (what->a2.i) + switch (what->a[1].i) { case SA_FROM: res.val.ip = rta->from; break; case SA_GW: res.val.ip = rta->nh.gw; break; @@ -323,7 +323,7 @@ { struct rta *rta = (*fs->rte)->attrs; - switch (what->a2.i) + switch (what->a[1].i) { case SA_FROM: rta->from = v1.val.ip; @@ -383,7 +383,7 @@ ACCESS_RTE; ACCESS_EATTRS; { - u16 code = what->a2.i; + u16 code = what->a[1].i; int f_type = what->aux >> 8; eattr *e = ea_find(*fs->eattrs, code); @@ -473,7 +473,7 @@ ARG_ANY(1); { struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - u16 code = what->a2.i; + u16 code = what->a[1].i; int f_type = what->aux >> 8; l->next = NULL; @@ -659,21 +659,21 @@ return F_RETURN; case FI_CALL: ARG_ANY_T(1,0); - fret = interpret(fs, what->a2.p); + fret = interpret(fs, what->a[1].p); if (fret > F_RETURN) return fret; break; case FI_CLEAR_LOCAL_VARS: /* Clear local variables */ - for (sym = what->a1.p; sym != NULL; sym = sym->aux2) + for (sym = what->a[0].p; sym != NULL; sym = sym->aux2) ((struct f_val *) sym->def)->type = T_VOID; break; case FI_SWITCH: ARG_ANY(1); { - struct f_tree *t = find_tree(what->a2.p, v1); + struct f_tree *t = find_tree(what->a[1].p, v1); if (!t) { v1.type = T_VOID; - t = find_tree(what->a2.p, v1); + t = find_tree(what->a[1].p, v1); if (!t) { debug( "No else statement?\n"); break; diff --git a/filter/f-util.c b/filter/f-util.c index ee9490b4..d7678fa1 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -31,7 +31,7 @@ f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da) { struct f_inst *ret = f_new_inst(fi_code); ret->aux = (da.f_type << 8) | da.type; - ret->a2.i = da.ea_code; + ret->a[1].i = da.ea_code; return ret; } @@ -40,8 +40,8 @@ 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; + ret->a[1].i = sa.sa_code; + ret->a[0].i = sa.readonly; return ret; } @@ -56,10 +56,10 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s *get_dyn = f_new_inst_da(FI_EA_GET, da); oper->aux = operation_aux; - oper->a1.p = get_dyn; - oper->a2.p = argument; + oper->a[0].p = get_dyn; + oper->a[1].p = argument; - set_dyn->a1.p = oper; + set_dyn->a[0].p = oper; return set_dyn; } diff --git a/filter/filter.c b/filter/filter.c index 3b310257..c54bedea 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -18,8 +18,8 @@ * A filter is represented by a tree of &f_inst structures, one structure per * "instruction". Each &f_inst contains @code, @aux value which is * usually the data type this instruction operates on and two generic - * arguments (@a1, @a2). Some instructions contain pointer(s) to other - * instructions in their (@a1, @a2) fields. + * arguments (@a[0], @a[1]). Some instructions contain pointer(s) to other + * instructions in their (@a[0], @a[1]) fields. * * Filters use a &f_val structure for their data. Each &f_val * contains type and value (types are constants prefixed with %T_). Few @@ -651,7 +651,7 @@ interpret(struct filter_state *fs, struct f_inst *what) return F_ERROR; \ } while(0) -#define ARG_ANY_T(n, tt) INTERPRET(what->a##n.p, tt) +#define ARG_ANY_T(n, tt) INTERPRET(what->a[n-1].p, tt) #define ARG_ANY(n) ARG_ANY_T(n, n) #define ARG_T(n,tt,t) do { \ @@ -677,7 +677,7 @@ interpret(struct filter_state *fs, struct f_inst *what) #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) -#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a2.i)) +#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i)) #include "filter/f-inst.c" @@ -695,14 +695,14 @@ interpret(struct filter_state *fs, struct f_inst *what) #define ARG(n) \ - if (!i_same(f1->a##n.p, f2->a##n.p)) \ + if (!i_same(f1->a[n-1].p, f2->a[n-1].p)) \ return 0; #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; +#define A2_SAME if (f1->a[1].i != f2->a[1].i) return 0; /* * i_same - function that does real comparing of instruction trees, you should call filter_same from outside @@ -735,7 +735,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) case FI_LT: case FI_LTE: TWOARGS; break; - case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a1.p, f2->a1.p)) return 0; break; + case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a[0].p, f2->a[0].p)) return 0; break; case FI_NOT: ONEARG; break; case FI_NOT_MATCH: @@ -751,8 +751,8 @@ i_same(struct f_inst *f1, struct f_inst *f2) ARG(2); { struct symbol *s1, *s2; - s1 = f1->a1.p; - s2 = f2->a1.p; + s1 = f1->a[0].p; + s2 = f2->a[0].p; if (strcmp(s1->name, s2->name)) return 0; if (s1->class != s2->class) @@ -764,17 +764,17 @@ i_same(struct f_inst *f1, struct f_inst *f2) switch (f1->aux) { case T_PREFIX_SET: - if (!trie_same(f1->a2.p, f2->a2.p)) + if (!trie_same(f1->a[1].p, f2->a[1].p)) return 0; break; case T_SET: - if (!same_tree(f1->a2.p, f2->a2.p)) + if (!same_tree(f1->a[1].p, f2->a[1].p)) return 0; break; case T_STRING: - if (strcmp(f1->a2.p, f2->a2.p)) + if (strcmp(f1->a[1].p, f2->a[1].p)) return 0; break; @@ -784,12 +784,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) break; case FI_CONSTANT_INDIRECT: - if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) + if (!val_same(* (struct f_val *) f1->a[0].p, * (struct f_val *) f2->a[0].p)) return 0; break; case FI_VARIABLE: - if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) + if (strcmp((char *) f1->a[1].p, (char *) f2->a[1].p)) return 0; break; case FI_PRINT: case FI_LENGTH: ONEARG; break; @@ -812,12 +812,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) 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)) + if (!i_same(f1->a[1].p, f2->a[1].p)) return 0; - f2->a2.p = f1->a2.p; + f2->a[1].p = f1->a[1].p; break; 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_SWITCH: ONEARG; if (!same_tree(f1->a[1].p, f2->a[1].p)) return 0; break; case FI_IP_MASK: TWOARGS; break; case FI_PATH_PREPEND: TWOARGS; break; case FI_CLIST_ADD_DEL: TWOARGS; break; diff --git a/filter/filter.h b/filter/filter.h index 8728f679..8dd531b1 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -90,20 +90,13 @@ struct f_inst { /* Instruction */ union { uint i; void *p; - } a1; /* The first argument */ - union { - uint i; - void *p; - } a2; /* The second argument */ - union { - int i; - void *p; - } a3; /* The third argument */ + } a[3]; /* The three arguments */ int lineno; }; -#define arg1 a1.p -#define arg2 a2.p +#define arg1 a[0].p +#define arg2 a[1].p +#define arg3 a[2].p /* Not enough fields in f_inst for three args used by roa_check() */ struct f_inst_roa_check { diff --git a/filter/filter_test.c b/filter/filter_test.c index b319225b..32555d82 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -62,7 +62,7 @@ bt_assert_filter(int result, struct f_inst *assert) bt_suit_case_result = 0; } - bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a2.p); + bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a[1].p); } int From ca2ee91a80aa87b7f18898c28e93ff22cebf73d7 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 15:25:04 +0100 Subject: [PATCH 13/88] Filter refactoring: The constant f_val is simply included inside the instruction With 32 bits, size of the args is 12 bytes, the f_val is 20 bytes. With 64 bits, size of the args is 24 bytes, the f_val the same. This is not so nice on 32 bits, anyway the f_inst itself is 24 vs. 32 bytes and the overall size of filters must be 32k of instructions to get to one megabyte of RAM eaten by f_inst. Therefore it seems to be improbable for common user to get into problems with this change. --- filter/config.Y | 91 ++++++++++++++++++++++--------------------------- filter/f-inst.c | 11 +----- filter/filter.h | 76 +++++++++++++++++++++-------------------- 3 files changed, 80 insertions(+), 98 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 20a19075..e1f3fec8 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -189,15 +189,17 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2) struct f_inst *rv; if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) { - if ((t1->aux != T_INT) || (t2->aux != T_INT)) + if ((t1->val.type != T_INT) || (t2->val.type != T_INT)) cf_error( "Can't operate with value of non-integer type in pair constructor"); check_u16(t1->a[1].i); check_u16(t2->a[1].i); rv = f_new_inst(FI_CONSTANT); - rv->aux = T_PAIR; - rv->a[1].i = pair(t1->a[1].i, t2->a[1].i); + rv->val = (struct f_val) { + .type = T_PAIR, + .val.i = pair(t1->a[1].i, t2->a[1].i), + }; } else { rv = f_new_inst(FI_PAIR_CONSTRUCT); @@ -217,26 +219,12 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) if (tk->fi_code == FI_CONSTANT) { c1 = 1; - - if (tk->aux == T_INT) { - ipv4_used = 0; key = tk->a[1].i; - } - else if (tk->aux == T_QUAD) { - ipv4_used = 1; key = tk->a[1].i; - } - else - cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); - } - - /* IP->Quad implicit conversion */ - else if (tk->fi_code == FI_CONSTANT_INDIRECT) { - c1 = 1; - struct f_val *val = tk->a[0].p; + struct f_val *val = &(tk->val); if (val->type == T_INT) { ipv4_used = 0; key = val->val.i; } - else if (val->type == T_QUAD) { + else if (tk->val.type == T_QUAD) { ipv4_used = 1; key = val->val.i; } else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) { @@ -247,10 +235,10 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) } if (tv->fi_code == FI_CONSTANT) { - if (tv->aux != T_INT) + if (tv->val.type != T_INT) cf_error("Can't operate with value of non-integer type in EC constructor"); c2 = 1; - val2 = tv->a[1].i; + val2 = tv->val.val.i; } if (c1 && c2) { @@ -271,11 +259,11 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) ec = ec_as4(kind, key, val2); } - NEW_F_VAL; - rv = f_new_inst(FI_CONSTANT_INDIRECT); - rv->a[0].p = val; - val->type = T_EC; - val->val.ec = ec; + rv = f_new_inst(FI_CONSTANT); + rv->val = (struct f_val) { + .type = T_EC, + .val.ec = ec, + }; } else { rv = f_new_inst(FI_EC_CONSTRUCT); @@ -293,15 +281,14 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) struct f_inst *rv; if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) { - if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) + if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT)) cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); - rv = f_new_inst(FI_CONSTANT_INDIRECT); - - NEW_F_VAL; - rv->a[0].p = val; - val->type = T_LC; - val->val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i }; + rv = f_new_inst(FI_CONSTANT); + rv->val = (struct f_val) { + .type = T_LC, + .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i }, + }; } else { @@ -325,12 +312,11 @@ f_generate_path_mask(struct f_path_mask *t) } } - NEW_F_VAL; - val->type = T_PATH_MASK; - val->val.path_mask = t; - - struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT); - rv->a[0].p = val; + struct f_inst *rv = f_new_inst(FI_CONSTANT); + rv->val = (struct f_val) { + .type = T_PATH_MASK, + .val.path_mask = t, + }; return rv; } @@ -771,8 +757,6 @@ switch_body: /* EMPTY */ { $$ = NULL; } } ; -/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $3; } */ - bgp_path_expr: symbol { $$ = $1; } | '(' term ')' { $$ = $2; } @@ -792,16 +776,21 @@ bgp_path_tail: ; constant: - NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $1; } - | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 1; } - | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 0; } - | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a[1].p = $1; } - | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a[0].p = val; *val = $1; } - | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a[0].p = val; } - | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a[0].p = val; } - | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a[1].p = build_tree($2); DBG( "ook\n" ); } - | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a[1].p = $2; } - | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a[1].i = $1 & 0xffff; } + NUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_INT, .val.i = $1, }; } + | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 1, }; } + | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 0, }; } + | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_STRING, .val.s = $1, }; } + | fipa { $$ = f_new_inst(FI_CONSTANT); $$->val = $1; } + | VPN_RD { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_RD, .val.ec = $1, }; } + | net_ { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_NET, .val.net = $1, }; } + | '[' set_items ']' { + DBG( "We've got a set here..." ); + $$ = f_new_inst(FI_CONSTANT); + $$->val = (struct f_val) { .type = T_SET, .val.t = build_tree($2), }; + DBG( "ook\n" ); + } + | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }; } + | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }; } ; constructor: diff --git a/filter/f-inst.c b/filter/f-inst.c index a7d381c2..fb2f043c 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -240,16 +240,7 @@ /* some constants have value in a[1], some in *a[0].p, strange. */ case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */ - res.type = what->aux; - - if (res.type == T_PREFIX_SET) - res.val.ti = what->a[1].p; - else if (res.type == T_SET) - res.val.t = what->a[1].p; - else if (res.type == T_STRING) - res.val.s = what->a[1].p; - else - res.val.i = what->a[1].i; + res = what->val; break; case FI_VARIABLE: case FI_CONSTANT_INDIRECT: diff --git a/filter/filter.h b/filter/filter.h index 8dd531b1..e483d223 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -14,6 +14,39 @@ #include "nest/route.h" #include "nest/attrs.h" +struct f_prefix { + net_addr net; + u8 lo, hi; +}; + +struct f_val { + int type; /* T_* */ + union { + uint i; + u64 ec; + lcomm lc; + ip_addr ip; + const net_addr *net; + char *s; + struct f_tree *t; + struct f_trie *ti; + struct adata *ad; + struct f_path_mask *path_mask; + } val; +}; + +struct f_dynamic_attr { + int type; + int f_type; + int ea_code; +}; + +struct f_static_attr { + int f_type; + int sa_code; + int readonly; +}; + /* Filter instruction types */ #define FI__TWOCHAR(a,b) ((a<<8) | b) @@ -88,9 +121,12 @@ struct f_inst { /* Instruction */ enum f_instruction_code fi_code; u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ union { - uint i; - void *p; - } a[3]; /* The three arguments */ + union { + uint i; + void *p; + } a[3]; /* The three arguments */ + struct f_val val; /* The value if FI_CONSTANT */ + }; int lineno; }; @@ -103,40 +139,6 @@ struct f_inst_roa_check { struct f_inst i; struct rtable_config *rtc; }; - -struct f_prefix { - net_addr net; - u8 lo, hi; -}; - -struct f_val { - int type; /* T_* */ - union { - uint i; - u64 ec; - lcomm lc; - ip_addr ip; - const net_addr *net; - char *s; - struct f_tree *t; - struct f_trie *ti; - struct adata *ad; - struct f_path_mask *path_mask; - } val; -}; - -struct f_dynamic_attr { - int type; - int f_type; - int ea_code; -}; - -struct f_static_attr { - int f_type; - int sa_code; - int readonly; -}; - struct filter { char *name; struct f_inst *root; From 8436040735b84bb185311125bfc91375f740fd86 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 16:07:59 +0100 Subject: [PATCH 14/88] Filter refactoring: Drop the roa check specific f_inst --- filter/f-inst.c | 2 +- filter/f-util.c | 12 +++++------- filter/filter.c | 6 +++--- filter/filter.h | 6 +----- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index fb2f043c..37de2a1e 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -890,7 +890,7 @@ as_path_get_last(e->u.ptr, &as); } - struct rtable *table = ((struct f_inst_roa_check *) what)->rtc->table; + struct rtable *table = what->a[2].rtc->table; if (!table) runtime("Missing ROA table"); diff --git a/filter/f-util.c b/filter/f-util.c index d7678fa1..11a5e97e 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -66,18 +66,16 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s struct f_inst * 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.fi_code = FI_ROA_CHECK; - ret->i.lineno = ifs->lino; - ret->i.arg1 = prefix; - ret->i.arg2 = asn; + struct f_inst *ret = f_new_inst(FI_ROA_CHECK); + ret->arg1 = prefix; + ret->arg2 = asn; /* prefix == NULL <-> asn == NULL */ if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) cf_error("%s is not a ROA table", table->name); - ret->rtc = table; + ret->arg3 = table; - return &ret->i; + return ret; } static const char * const f_instruction_name_str[] = { diff --git a/filter/filter.c b/filter/filter.c index c54bedea..c2184f0b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -826,9 +826,9 @@ i_same(struct f_inst *f1, struct f_inst *f2) case FI_AS_PATH_LAST_NAG: ONEARG; break; case FI_ROA_CHECK: TWOARGS; - /* 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)) + /* FIXME: ROA check results may change anyway */ + if (strcmp(f1->a[2].rtc->name, + f2->a[2].rtc->name)) return 0; break; case FI_FORMAT: ONEARG; break; diff --git a/filter/filter.h b/filter/filter.h index e483d223..06e87a8f 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -124,6 +124,7 @@ struct f_inst { /* Instruction */ union { uint i; void *p; + struct rtable_config *rtc; } a[3]; /* The three arguments */ struct f_val val; /* The value if FI_CONSTANT */ }; @@ -134,11 +135,6 @@ struct f_inst { /* Instruction */ #define arg2 a[1].p #define arg3 a[2].p -/* Not enough fields in f_inst for three args used by roa_check() */ -struct f_inst_roa_check { - struct f_inst i; - struct rtable_config *rtc; -}; struct filter { char *name; struct f_inst *root; From 967b88d9388b3800efed45798542cd0b41f2b903 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 20 Dec 2018 16:25:54 +0100 Subject: [PATCH 15/88] Filter refactoring: The instructions are converted to the switch body by M4 --- filter/Makefile | 7 ++ filter/f-inst.c | 216 ++++++++++++++++++++++---------------------- filter/filter.c | 9 +- filter/filter.h | 2 +- filter/interpret.m4 | 16 ++++ 5 files changed, 139 insertions(+), 111 deletions(-) create mode 100644 filter/interpret.m4 diff --git a/filter/Makefile b/filter/Makefile index 6bada8ca..0979a34f 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -3,6 +3,13 @@ obj := $(src-o-files) $(all-daemon) $(cf-local) +M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) + +$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)filter.o: $(o)f-inst-interpret.c + tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) tests_objs := $(tests_objs) $(src-o-files) diff --git a/filter/f-inst.c b/filter/f-inst.c index 37de2a1e..ef5d4f06 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -10,38 +10,38 @@ */ /* Binary operators */ - case FI_ADD: + INST(FI_ADD) { ARG_T(1,0,T_INT); ARG_T(2,1,T_INT); res.val.i += v1.val.i; - break; - case FI_SUBTRACT: + } + INST(FI_SUBTRACT) { ARG_T(1,0,T_INT); ARG_T(2,1,T_INT); res.val.i -= v1.val.i; - break; - case FI_MULTIPLY: + } + INST(FI_MULTIPLY) { ARG_T(1,0,T_INT); ARG_T(2,1,T_INT); res.val.i *= v1.val.i; - break; - case FI_DIVIDE: + } + INST(FI_DIVIDE) { ARG_T(1,0,T_INT); ARG_T(2,1,T_INT); if (v1.val.i == 0) runtime( "Mother told me not to divide by 0" ); res.val.i /= v1.val.i; - break; - case FI_AND: + } + INST(FI_AND) { ARG_T(1,0,T_BOOL); if (res.val.i) ARG_T(2,0,T_BOOL); - break; - case FI_OR: + } + INST(FI_OR) { ARG_T(1,0,T_BOOL); if (!res.val.i) ARG_T(2,0,T_BOOL); - break; - case FI_PAIR_CONSTRUCT: + } + INST(FI_PAIR_CONSTRUCT) { ARG(1,T_INT); ARG(2,T_INT); u1 = v1.val.i; @@ -50,9 +50,9 @@ runtime( "Can't operate with value out of bounds in pair constructor" ); res.val.i = (u1 << 16) | u2; res.type = T_PAIR; - break; + } - case FI_EC_CONSTRUCT: + INST(FI_EC_CONSTRUCT) { { ARG_ANY(1); ARG(2, T_INT); @@ -94,10 +94,10 @@ if (check && (val > 0xFFFF)) runtime("Can't operate with value out of bounds in EC constructor"); - break; + } } - case FI_LC_CONSTRUCT: + INST(FI_LC_CONSTRUCT) { { ARG(1, T_INT); ARG(2, T_INT); @@ -106,10 +106,10 @@ res.type = T_LC; res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i }; - break; + } } - case FI_PATHMASK_CONSTRUCT: + INST(FI_PATHMASK_CONSTRUCT) { { struct f_path_mask *tt = what->a[0].p, *vbegin, **vv = &vbegin; @@ -132,26 +132,26 @@ } res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin }; - break; + } } /* Relational operators */ - case FI_NEQ: + INST(FI_NEQ) { ARG_ANY(1); ARG_ANY(2); res.type = T_BOOL; res.val.i = !val_same(v1, v2); - break; + } - case FI_EQ: + INST(FI_EQ) { ARG_ANY(1); ARG_ANY(2); res.type = T_BOOL; res.val.i = val_same(v1, v2); - break; + } - case FI_LT: + INST(FI_LT) { ARG_ANY(1); ARG_ANY(2); i = val_compare(v1, v2); @@ -159,9 +159,9 @@ runtime( "Can't compare values of incompatible types" ); res.type = T_BOOL; res.val.i = (i == -1); - break; + } - case FI_LTE: + INST(FI_LTE) { ARG_ANY(1); ARG_ANY(2); i = val_compare(v1, v2); @@ -169,14 +169,14 @@ runtime( "Can't compare values of incompatible types" ); res.type = T_BOOL; res.val.i = (i != 1); - break; + } - case FI_NOT: + INST(FI_NOT) { ARG_T(1,0,T_BOOL); res.val.i = !res.val.i; - break; + } - case FI_MATCH: + INST(FI_MATCH) { ARG_ANY(1); ARG_ANY(2); res.type = T_BOOL; @@ -184,9 +184,9 @@ if (res.val.i == CMP_ERROR) runtime( "~ applied on unknown type pair" ); res.val.i = !!res.val.i; - break; + } - case FI_NOT_MATCH: + INST(FI_NOT_MATCH) { ARG_ANY(1); ARG_ANY(2); res.type = T_BOOL; @@ -194,14 +194,14 @@ if (res.val.i == CMP_ERROR) runtime( "!~ applied on unknown type pair" ); res.val.i = !res.val.i; - break; + } - case FI_DEFINED: + INST(FI_DEFINED) { ARG_ANY(1); res.type = T_BOOL; res.val.i = (v1.type != T_VOID) && !undef_value(v1); - break; - case FI_TYPE: + } + INST(FI_TYPE) { ARG_ANY(1); /* There may be more types supporting this operation */ switch (v1.type) { @@ -212,15 +212,15 @@ default: runtime( "Can't determine type of this item" ); } - break; - case FI_IS_V4: + } + INST(FI_IS_V4) { ARG(1, T_IP); res.type = T_BOOL; res.val.i = ipa_is_ip4(v1.val.ip); - break; + } /* Set to indirect value, a[0] = variable, a[1] = value */ - case FI_SET: + INST(FI_SET) { ARG_ANY(2); sym = what->a[0].p; vp = sym->def; @@ -236,31 +236,30 @@ runtime( "Assigning to variable of incompatible type" ); } *vp = v2; - break; + } /* some constants have value in a[1], some in *a[0].p, strange. */ - case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */ + INST(FI_CONSTANT) { /* integer (or simple type) constant, string, set, or prefix_set */ res = what->val; - break; - case FI_VARIABLE: - case FI_CONSTANT_INDIRECT: + } + INST(FI_VARIABLE) { res = * ((struct f_val *) what->a[0].p); - break; - case FI_PRINT: + } + INST(FI_CONSTANT_INDIRECT) { + res = * ((struct f_val *) what->a[0].p); + } + INST(FI_PRINT) { ARG_ANY(1); val_format(v1, &fs->buf); - break; - case FI_CONDITION: + } + INST(FI_CONDITION) { ARG_T(1, 0, T_BOOL); if (res.val.i) ARG_ANY_T(2,0); else ARG_ANY_T(3,0); - break; - case FI_NOP: - debug( "No operation\n" ); - break; - case FI_PRINT_AND_DIE: + } + INST(FI_PRINT_AND_DIE) { ARG_ANY(1); if ((what->a[1].i == F_NOP || (what->a[1].i != F_NONL && what->a[0].p)) && !(fs->flags & FF_SILENT)) @@ -280,8 +279,8 @@ default: bug( "unknown return type: Can't happen"); } - break; - case FI_RTA_GET: /* rta access */ + } + INST(FI_RTA_GET) { /* rta access */ { ACCESS_RTE; struct rta *rta = (*fs->rte)->attrs; @@ -303,8 +302,8 @@ bug("Invalid static attribute access (%x)", res.type); } } - break; - case FI_RTA_SET: + } + INST(FI_RTA_SET) { ACCESS_RTE; ARG_ANY(1); if (what->aux != v1.type) @@ -369,8 +368,8 @@ bug("Invalid static attribute access (%x)", res.type); } } - break; - case FI_EA_GET: /* Access to extended attributes */ + } + INST(FI_EA_GET) { /* Access to extended attributes */ ACCESS_RTE; ACCESS_EATTRS; { @@ -457,8 +456,8 @@ bug("Unknown type in e,a"); } } - break; - case FI_EA_SET: + } + INST(FI_EA_SET) { ACCESS_RTE; ACCESS_EATTRS; ARG_ANY(1); @@ -551,21 +550,21 @@ l->next = *fs->eattrs; *fs->eattrs = l; } - break; - case FI_PREF_GET: + } + INST(FI_PREF_GET) { ACCESS_RTE; res.type = T_INT; res.val.i = (*fs->rte)->pref; - break; - case FI_PREF_SET: + } + INST(FI_PREF_SET) { ACCESS_RTE; ARG(1,T_INT); if (v1.val.i > 0xFFFF) runtime( "Setting preference value out of bounds" ); f_rte_cow(fs); (*fs->rte)->pref = v1.val.i; - break; - case FI_LENGTH: /* Get length of */ + } + INST(FI_LENGTH) { /* Get length of */ ARG_ANY(1); res.type = T_INT; switch(v1.type) { @@ -576,8 +575,8 @@ case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break; default: runtime( "Prefix, path, clist or eclist expected" ); } - break; - case FI_SADR_SRC: /* Get SADR src prefix */ + } + INST(FI_SADR_SRC) { /* Get SADR src prefix */ ARG(1, T_NET); if (!net_is_sadr(v1.val.net)) runtime( "SADR expected" ); @@ -590,8 +589,8 @@ res.type = T_NET; res.val.net = src; } - break; - case FI_ROA_MAXLEN: /* Get ROA max prefix length */ + } + INST(FI_ROA_MAXLEN) { /* Get ROA max prefix length */ ARG(1, T_NET); if (!net_is_roa(v1.val.net)) runtime( "ROA expected" ); @@ -600,8 +599,8 @@ 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 FI_ROA_ASN: /* Get ROA ASN */ + } + INST(FI_ROA_ASN) { /* Get ROA ASN */ ARG(1, T_NET); if (!net_is_roa(v1.val.net)) runtime( "ROA expected" ); @@ -610,55 +609,56 @@ 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 FI_IP: /* Convert prefix to ... */ + } + INST(FI_IP) { /* Convert prefix to ... */ ARG(1, T_NET); res.type = T_IP; res.val.ip = net_prefix(v1.val.net); - break; - case FI_ROUTE_DISTINGUISHER: + } + INST(FI_ROUTE_DISTINGUISHER) { ARG(1, T_NET); 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 */ + } + INST(FI_AS_PATH_FIRST) { /* Get first ASN from AS PATH */ ARG(1, T_PATH); as = 0; as_path_get_first(v1.val.ad, &as); res.type = T_INT; res.val.i = as; - break; - case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */ + } + INST(FI_AS_PATH_LAST) { /* Get last ASN from AS PATH */ ARG(1, T_PATH); as = 0; as_path_get_last(v1.val.ad, &as); res.type = T_INT; res.val.i = as; - break; - case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */ + } + INST(FI_AS_PATH_LAST_NAG) { /* Get last ASN from non-aggregated part of AS PATH */ ARG(1, T_PATH); res.type = T_INT; res.val.i = as_path_get_last_nonaggregated(v1.val.ad); - break; - case FI_RETURN: + } + INST(FI_RETURN) { ARG_ANY_T(1,0); return F_RETURN; - case FI_CALL: + } + INST(FI_CALL) { ARG_ANY_T(1,0); fret = interpret(fs, what->a[1].p); if (fret > F_RETURN) return fret; - break; - case FI_CLEAR_LOCAL_VARS: /* Clear local variables */ + } + INST(FI_CLEAR_LOCAL_VARS) { /* Clear local variables */ for (sym = what->a[0].p; sym != NULL; sym = sym->aux2) ((struct f_val *) sym->def)->type = T_VOID; - break; - case FI_SWITCH: + } + INST(FI_SWITCH) { ARG_ANY(1); { struct f_tree *t = find_tree(what->a[1].p, v1); @@ -676,8 +676,8 @@ if (fret >= F_RETURN) return fret; } - break; - case FI_IP_MASK: /* IP.MASK(val) */ + } + INST(FI_IP_MASK) { /* IP.MASK(val) */ ARG(1, T_IP); ARG(2, T_INT); @@ -685,21 +685,21 @@ 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 FI_EMPTY: /* Create empty attribute */ + INST(FI_EMPTY) { /* Create empty attribute */ res.type = what->aux; res.val.ad = adata_empty(fs->pool, 0); - break; - case FI_PATH_PREPEND: /* Path prepend */ + } + INST(FI_PATH_PREPEND) { /* Path prepend */ ARG(1, T_PATH); ARG(2, T_INT); res.type = T_PATH; res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); - break; + } - case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */ + INST(FI_CLIST_ADD_DEL) { /* (Extended) Community list add or delete */ ARG_ANY(1); ARG_ANY(2); if (v1.type == T_PATH) @@ -864,9 +864,9 @@ else runtime("Can't add/delete to non-[e|l]clist"); - break; + } - case FI_ROA_CHECK: /* ROA Check */ + INST(FI_ROA_CHECK) { /* ROA Check */ if (what->arg1) { ARG(1, T_NET); @@ -904,23 +904,21 @@ else res.val.i = net_roa_check(table, v1.val.net, as); - break; + } - case FI_FORMAT: /* Format */ + INST(FI_FORMAT) { /* Format */ ARG_ANY(1); res.type = T_STRING; res.val.s = val_format_str(fs, v1); - break; + } - case FI_ASSERT: /* Birdtest Assert */ + INST(FI_ASSERT) { /* Birdtest Assert */ ARG(1, T_BOOL); res.type = v1.type; res.val = v1.val; CALL(bt_assert_hook, res.val.i, what); - break; + } - default: - bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); diff --git a/filter/filter.c b/filter/filter.c index c2184f0b..308792b9 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -679,7 +679,14 @@ interpret(struct filter_state *fs, struct f_inst *what) #define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i)) -#include "filter/f-inst.c" + case FI_NOP: + bug("This shall not happen"); + +#include "filter/f-inst-interpret.c" + + break; + default: + bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); #undef res #undef runtime diff --git a/filter/filter.h b/filter/filter.h index 06e87a8f..594c9511 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -51,6 +51,7 @@ struct f_static_attr { #define FI__TWOCHAR(a,b) ((a<<8) | b) #define FI__LIST \ + F(FI_NOP, 0, '0') \ F(FI_ADD, 0, '+') \ F(FI_SUBTRACT, 0, '-') \ F(FI_MULTIPLY, 0, '*') \ @@ -77,7 +78,6 @@ struct f_static_attr { 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') \ diff --git a/filter/interpret.m4 b/filter/interpret.m4 new file mode 100644 index 00000000..d1c83389 --- /dev/null +++ b/filter/interpret.m4 @@ -0,0 +1,16 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Generator of Filter Instructions +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(INST, `break; case $1:') + +m4_changequote([[,]]) +m4_divert(0) From 4c553c5a5b40c21ba67bd82455e79678b204cd07 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 27 Dec 2018 14:26:11 +0100 Subject: [PATCH 16/88] Filter refactoring: dropped the recursion from the interpreter This is a major change of how the filters are interpreted. If everything works how it should, it should not affect you unless you are hacking the filters themselves. Anyway, this change should make a huge improvement in the filter performance as previous benchmarks showed that our major problem lies in the recursion itself. There are also some changes in nest and protocols, related mostly to spreading const declarations throughout the whole BIRD and also to refactored dynamic attribute definitions. The need of these came up during the whole work and it is too difficult to split out these not-so-related changes. --- conf/confbase.Y | 5 +- doc/bird.sgml | 2 +- filter/Makefile | 16 +- filter/config.Y | 185 ++++---- filter/dump.m4 | 43 ++ filter/f-inst.c | 1007 ++++++++++++++++++++-------------------- filter/f-util.c | 29 +- filter/filter.c | 544 +++++++++++++--------- filter/filter.h | 349 +++++++++----- filter/filter_test.c | 7 +- filter/interpret.m4 | 57 ++- filter/line-size.m4 | 30 ++ filter/postfixify.m4 | 55 +++ filter/same.m4 | 56 +++ filter/tree.c | 30 +- filter/tree_test.c | 10 +- filter/trie.c | 14 +- lib/ip.h | 4 +- nest/a-path.c | 68 +-- nest/a-path_test.c | 18 +- nest/a-set.c | 60 +-- nest/a-set_test.c | 37 +- nest/attrs.h | 109 +++-- nest/cmds.c | 5 +- nest/cmds.h | 4 +- nest/config.Y | 6 +- nest/route.h | 6 +- nest/rt-attr.c | 16 +- proto/babel/config.Y | 2 +- proto/bgp/attrs.c | 41 +- proto/bgp/bgp.h | 4 +- proto/bgp/config.Y | 24 +- proto/bgp/packets.c | 6 +- proto/ospf/config.Y | 8 +- proto/radv/config.Y | 4 +- proto/rip/config.Y | 4 +- proto/static/config.Y | 7 +- proto/static/static.c | 2 +- proto/static/static.h | 2 +- sysdep/linux/krt-sys.h | 21 - sysdep/linux/netlink.Y | 58 +-- sysdep/linux/netlink.c | 9 +- sysdep/unix/krt.Y | 4 +- 43 files changed, 1699 insertions(+), 1269 deletions(-) create mode 100644 filter/dump.m4 create mode 100644 filter/line-size.m4 create mode 100644 filter/postfixify.m4 create mode 100644 filter/same.m4 diff --git a/conf/confbase.Y b/conf/confbase.Y index 3d573e10..492ecd08 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -55,7 +55,6 @@ CF_DECLS struct f_tree *e; struct f_trie *trie; struct f_val v; - struct f_path_mask *h; struct password_item *p; struct rt_show_data *ra; struct sym_show_data *sd; @@ -124,14 +123,14 @@ conf: definition ; definition: DEFINE SYM '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); - if (f_eval($4, cfg_mem, val) > F_RETURN) cf_error("Runtime error"); + if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); cf_define_symbol($2, SYM_CONSTANT | val->type, val); } ; expr: NUM - | '(' term ')' { $$ = f_eval_int($2); } + | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } | SYM { if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected"); $$ = SYM_VAL($1).i; } diff --git a/doc/bird.sgml b/doc/bird.sgml index e531da40..8594b930 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -3982,7 +3982,7 @@ definitions, prefix definitions and DNS definitions: RAdv protocol could be configured to change its behavior based on availability of routes. When this option is used, the protocol waits in suppressed state until a $@ -$(o)filter.o: $(o)f-inst-interpret.c +$(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/config.Y b/filter/config.Y index e1f3fec8..a79b1582 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -158,20 +158,20 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) static inline struct f_inst * f_generate_empty(struct f_dynamic_attr dyn) { - struct f_inst *e = f_new_inst(FI_EMPTY); + struct f_inst *e = f_new_inst(FI_CONSTANT); switch (dyn.type & EAF_TYPE_MASK) { case EAF_TYPE_AS_PATH: - e->aux = T_PATH; + e->val = f_const_empty_path; break; case EAF_TYPE_INT_SET: - e->aux = T_CLIST; + e->val = f_const_empty_clist; break; case EAF_TYPE_EC_SET: - e->aux = T_ECLIST; + e->val = f_const_empty_eclist; break; case EAF_TYPE_LC_SET: - e->aux = T_LCLIST; + e->val = f_const_empty_lclist; break; default: cf_error("Can't empty that attribute"); @@ -302,23 +302,34 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) } static inline struct f_inst * -f_generate_path_mask(struct f_path_mask *t) +f_generate_path_mask(struct f_inst *t) { - for (struct f_path_mask *tt = t; tt; tt = tt->next) { - if (tt->kind == PM_ASN_EXPR) { - struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT); - mrv->a[0].p = t; - return mrv; - } + uint len = 0; + uint dyn = 0; + for (const struct f_inst *tt = t; tt; tt = tt->next) { + if (tt->fi_code != FI_CONSTANT) + dyn++; + len++; } - struct f_inst *rv = f_new_inst(FI_CONSTANT); - rv->val = (struct f_val) { - .type = T_PATH_MASK, - .val.path_mask = t, - }; + if (dyn) { + struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT); + pmc->a[0].p = t; + pmc->a[1].i = len; + return pmc; + } - return rv; + struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item)); + + uint i = 0; + for (const struct f_inst *tt = t; tt; tt = tt->next) + pm->item[i++] = tt->val.val.pmi; + + pm->len = i; + struct f_inst *pmc = f_new_inst(FI_CONSTANT); + pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, }; + + return pmc; } /* @@ -409,7 +420,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc THEN %nonassoc ELSE -%type term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr +%type term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter filter_body where_filter @@ -420,7 +431,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type set_atom switch_atom fipa %type fprefix %type decls declsn one_decl function_params -%type bgp_path bgp_path_tail %type get_cf_position CF_GRAMMAR @@ -438,7 +448,7 @@ filter_def: conf: filter_eval ; filter_eval: - EVAL term { f_eval_int($2); } + EVAL term { f_eval_int(f_postfixify($2)); } ; conf: custom_attr ; @@ -530,7 +540,7 @@ filter_body: function_body { struct filter *f = cfg_alloc(sizeof(struct filter)); f->name = NULL; - f->root = $1; + f->root = f_postfixify($1); $$ = f; } ; @@ -547,21 +557,25 @@ where_filter: WHERE term { /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ struct filter *f = cfg_alloc(sizeof(struct filter)); - struct f_inst *i, *acc, *rej; - acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ - acc->a[0].p = NULL; - acc->a[1].i = F_ACCEPT; - rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */ - rej->a[0].p = NULL; - rej->a[1].i = F_REJECT; - i = f_new_inst(FI_CONDITION); /* IF */ - i->a[0].p = $2; - i->a[1].p = acc; - i->a[2].p = rej; + struct f_inst acc = { + .fi_code = FI_PRINT_AND_DIE, + .a = { { .p = NULL }, { .i = F_ACCEPT } }, + .lineno = ifs->lino, + }; + struct f_inst rej = { + .fi_code = FI_PRINT_AND_DIE, + .a = { { .p = NULL }, { .i = F_REJECT } }, + .lineno = ifs->lino, + }; + struct f_inst i = { + .fi_code = FI_CONDITION, + .a = { { .p = $2 }, { .p = &acc }, { .p = &rej } }, + .lineno = ifs->lino, + }; f->name = NULL; - f->root = i; + f->root = f_postfixify(&i); $$ = f; - } + } ; function_params: @@ -587,7 +601,9 @@ function_def: $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); cf_push_scope($2); } function_params function_body { - $2->def = $5; + struct f_inst *vc = f_new_inst(FI_CONSTANT); + vc->val = (struct f_val) { .type = T_VOID }; + $2->def = f_postfixify_concat($5, vc, NULL); $2->aux2 = $4; DBG("Hmm, we've got one function here - %s\n", $2->name); cf_pop_scope(); @@ -639,7 +655,7 @@ set_atom: | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); + if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } | SYM { @@ -651,13 +667,13 @@ set_atom: switch_atom: NUM { $$.type = T_INT; $$.val.i = $1; } - | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); } + | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); } | fipa { $$ = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } ; cnum: - term { $$ = f_eval_int($1); } + term { $$ = f_eval_int(f_postfixify($1)); } pair_item: '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } @@ -744,15 +760,16 @@ switch_body: /* EMPTY */ { $$ = NULL; } | switch_body switch_items ':' cmds { /* Fill data fields */ struct f_tree *t; + struct f_line *line = f_postfixify($4); for (t = $2; t; t = t->left) - t->data = $4; + t->data = line; $$ = f_merge_items($1, $2); } | switch_body ELSECOL cmds { struct f_tree *t = f_new_tree(); t->from.type = t->to.type = T_VOID; t->right = t; - t->data = $3; + t->data = f_postfixify($3); $$ = f_merge_items($1, t); } ; @@ -767,11 +784,11 @@ bgp_path: ; bgp_path_tail: - NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } - | NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; } - | '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; } - | '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; } - | bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } + NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; } + | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; } + | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; } + | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; } + | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; } | { $$ = NULL; } ; @@ -831,12 +848,11 @@ symbol: switch ($1->class & 0xffff) { case SYM_CONSTANT_RANGE: $$ = f_new_inst(FI_CONSTANT_INDIRECT); - goto cv_common; + $$->a[0].p = $1; + break; case SYM_VARIABLE_RANGE: $$ = f_new_inst(FI_VARIABLE); - cv_common: - $$->a[0].p = $1->def; - $$->a[1].p = $1->name; + $$->a[0].p = $1; break; case SYM_ATTRIBUTE: $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); @@ -847,15 +863,15 @@ symbol: } static_attr: - 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_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); } - | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); } - | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); } - | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); } + FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); } + | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); } + | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); } + | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); } + | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); } + | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); } + | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); } + | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); } + | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); } ; term: @@ -908,42 +924,23 @@ term: | rtadot dynamic_attr '.' RESET{ } */ - | '+' 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; } + | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; } + | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; } + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; } - | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; } - | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; } - | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; } + | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; } + | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; } + | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; } - | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } - | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } + | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; } | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; } /* | term '.' LEN { $$->code = P('P','l'); } */ -/* function_call is inlined here */ - | SYM '(' var_list ')' { - struct symbol *sym; - struct f_inst *inst = $3; - if ($1->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); - DBG("You are calling function %s\n", $1->name); - $$ = f_new_inst(FI_CALL); - $$->a[0].p = inst; - $$->a[1].p = $1->def; - sym = $1->aux2; - while (sym || inst) { - if (!sym || !inst) - cf_error("Wrong number of arguments for function %s.", $1->name); - DBG( "You should pass parameter called %s\n", sym->name); - inst->a[0].p = sym; - sym = sym->aux2; - inst = inst->next; - } - } + | function_call ; break_command: @@ -1022,7 +1019,7 @@ cmd: } | rtadot static_attr '=' term ';' { $$ = f_new_inst_sa(FI_RTA_SET, $2); - if (!$$->a[0].i) + if ($$->sa.readonly) cf_error( "This static attribute is read-only."); $$->a[0].p = $4; } @@ -1036,7 +1033,7 @@ cmd: $$->a[0].p = NULL; } | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; } - | function_call ';' { $$ = $1; } + | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; } | CASE term '{' switch_body '}' { $$ = f_new_inst(FI_SWITCH); $$->a[0].p = $2; @@ -1044,10 +1041,10 @@ cmd: } | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } - | 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 ); } + | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); } + | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); } + | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); } + | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } ; diff --git a/filter/dump.m4 b/filter/dump.m4 new file mode 100644 index 00000000..913a7652 --- /dev/null +++ b/filter/dump.m4 @@ -0,0 +1,43 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Dumping instruction lines +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(INST, `m4_divert(1)break; case $1: +m4_divert(-1)')) +m4_define(LINE, `m4_divert(1)f_dump_line(item->lines[$2], indent + 1); +m4_divert(-1)') +m4_define(LINEP, `LINE($@)') +m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name); +m4_divert(-1)') +m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp)); +m4_divert(-1)') +m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp)); +m4_divert(-1)') +m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret); +m4_divert(-1)') +m4_define(ECS, `m4_divert(1)debug("%sec subtype %d\n", INDENT, item->ecs); +m4_divert(-1)') +m4_define(RTC, `m4_divert(1)debug("%sroute table %s\n", INDENT, item->rtc->name); +m4_divert(-1)') +m4_define(STATIC_ATTR, `m4_divert(1)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly); +m4_divert(-1)') +m4_define(DYNAMIC_ATTR, `m4_divert(1)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code); +m4_divert(-1)') +m4_define(DUMP, `m4_divert(1)$1m4_divert(-1)') + +m4_m4wrap(` +m4_divert(0)DNL +case FI_NOP: bug("This shall not happen"); +m4_undivert(1) +break; default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff); +') + +m4_changequote([[,]]) diff --git a/filter/f-inst.c b/filter/f-inst.c index ef5d4f06..02c88409 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -10,269 +10,282 @@ */ /* Binary operators */ - INST(FI_ADD) { - ARG_T(1,0,T_INT); - ARG_T(2,1,T_INT); - res.val.i += v1.val.i; - } - INST(FI_SUBTRACT) { - ARG_T(1,0,T_INT); - ARG_T(2,1,T_INT); - res.val.i -= v1.val.i; - } - INST(FI_MULTIPLY) { - ARG_T(1,0,T_INT); - ARG_T(2,1,T_INT); - res.val.i *= v1.val.i; - } - INST(FI_DIVIDE) { - ARG_T(1,0,T_INT); - ARG_T(2,1,T_INT); - if (v1.val.i == 0) runtime( "Mother told me not to divide by 0" ); - res.val.i /= v1.val.i; - } - INST(FI_AND) { - ARG_T(1,0,T_BOOL); - if (res.val.i) - ARG_T(2,0,T_BOOL); - } - INST(FI_OR) { - ARG_T(1,0,T_BOOL); - if (!res.val.i) - ARG_T(2,0,T_BOOL); - } - INST(FI_PAIR_CONSTRUCT) { + INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - u1 = v1.val.i; - u2 = v2.val.i; + res.val.i += v2.val.i; + RESULT_OK; + } + INST(FI_SUBTRACT, 2, 1) { + ARG(1,T_INT); + ARG(2,T_INT); + res.val.i -= v2.val.i; + RESULT_OK; + } + INST(FI_MULTIPLY, 2, 1) { + ARG(1,T_INT); + ARG(2,T_INT); + res.val.i *= v2.val.i; + RESULT_OK; + } + INST(FI_DIVIDE, 2, 1) { + ARG(1,T_INT); + ARG(2,T_INT); + if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); + res.val.i /= v2.val.i; + RESULT_OK; + } + INST(FI_AND, 1, 1) { + ARG(1,T_BOOL); + if (res.val.i) + LINE(2,0); + else + RESULT_OK; + } + INST(FI_OR, 1, 1) { + ARG(1,T_BOOL); + if (!res.val.i) + LINE(2,0); + else + RESULT_OK; + } + INST(FI_PAIR_CONSTRUCT, 2, 1) { + ARG(1,T_INT); + ARG(2,T_INT); + uint u1 = v1.val.i; + uint u2 = v2.val.i; if ((u1 > 0xFFFF) || (u2 > 0xFFFF)) runtime( "Can't operate with value out of bounds in pair constructor" ); - res.val.i = (u1 << 16) | u2; - res.type = T_PAIR; + RESULT(T_PAIR, i, (u1 << 16) | u2); + } + INST(FI_EC_CONSTRUCT, 2, 1) { + ARG_ANY(1); + ARG(2, T_INT); + ECS; + + int check, ipv4_used; + u32 key, val; + + if (v1.type == T_INT) { + ipv4_used = 0; key = v1.val.i; + } + else if (v1.type == T_QUAD) { + ipv4_used = 1; key = v1.val.i; + } + /* IP->Quad implicit conversion */ + else if (val_is_ip4(&v1)) { + ipv4_used = 1; key = ipa_to_u32(v1.val.ip); + } + else + runtime("Argument 1 of instruction FI_EC_CONSTRUCT must be integer or IPv4 address, got 0x%02x"); + + val = v2.val.i; + + if (ecs == EC_GENERIC) { + check = 0; RESULT(T_EC, ec, ec_generic(key, val)); + } + else if (ipv4_used) { + check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val)); + } + else if (key < 0x10000) { + check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val)); + } + else { + check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val)); + } + + if (check && (val > 0xFFFF)) + runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF); } - INST(FI_EC_CONSTRUCT) { - { - ARG_ANY(1); - ARG(2, T_INT); + INST(FI_LC_CONSTRUCT, 3, 1) { + ARG(1, T_INT); + ARG(2, T_INT); + ARG(3, T_INT); + RESULT(T_LC, lc, [[(lcomm) { v1.val.i, v2.val.i, v3.val.i }]]); + } - int check, ipv4_used; - u32 key, val; + INST(FI_PATHMASK_CONSTRUCT, 0, 1) { + ARG_ANY(1); + COUNT(2); + if (vstk.cnt < what->count) /* TODO: make this check systematic */ + runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count); - if (v1.type == T_INT) { - ipv4_used = 0; key = v1.val.i; + struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item)); + for (uint i=0; icount; i++) { +//#define pv vstk.val[vstk.cnt-i-1] +#define pv vstk.val[vstk.cnt - what->count + i] + switch (pv.type) { + case T_PATH_MASK_ITEM: + pm->item[i] = pv.val.pmi; + break; + case T_INT: + pm->item[i] = (struct f_path_mask_item) { + .asn = pv.val.i, + .kind = PM_ASN, + }; + break; + default: + runtime( "Error resolving path mask template: value not an integer" ); } - else if (v1.type == T_QUAD) { - ipv4_used = 1; key = v1.val.i; - } - /* IP->Quad implicit conversion */ - else if (val_is_ip4(v1)) { - ipv4_used = 1; key = ipa_to_u32(v1.val.ip); - } - else - runtime("Can't operate with key of non-integer/IPv4 type in EC constructor"); - - val = v2.val.i; - - /* XXXX */ - res.type = T_EC; - - if (what->aux == EC_GENERIC) { - check = 0; res.val.ec = ec_generic(key, val); - } - else if (ipv4_used) { - check = 1; res.val.ec = ec_ip4(what->aux, key, val); - } - else if (key < 0x10000) { - check = 0; res.val.ec = ec_as2(what->aux, key, val); - } - else { - check = 1; res.val.ec = ec_as4(what->aux, key, val); - } - - if (check && (val > 0xFFFF)) - runtime("Can't operate with value out of bounds in EC constructor"); - - } } - INST(FI_LC_CONSTRUCT) { - { - ARG(1, T_INT); - ARG(2, T_INT); - ARG(3, T_INT); + vstk.cnt -= what->count; + pm->len = what->count; - res.type = T_LC; - res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i }; - - } - } - - INST(FI_PATHMASK_CONSTRUCT) { - { - struct f_path_mask *tt = what->a[0].p, *vbegin, **vv = &vbegin; - - while (tt) { - *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask)); - if (tt->kind == PM_ASN_EXPR) { - INTERPRET((struct f_inst *) tt->val, 0); - (*vv)->kind = PM_ASN; - if (res.type != T_INT) { - runtime( "Error resolving path mask template: value not an integer" ); - return F_ERROR; - } - - (*vv)->val = res.val.i; - } else { - **vv = *tt; - } - tt = tt->next; - vv = &((*vv)->next); - } - - res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin }; - } - } + RESULT(T_PATH_MASK, path_mask, pm); + } /* Relational operators */ - INST(FI_NEQ) { + INST(FI_NEQ, 2, 1) { ARG_ANY(1); ARG_ANY(2); - res.type = T_BOOL; - res.val.i = !val_same(v1, v2); + RESULT(T_BOOL, i, !val_same(&v1, &v2)); } - INST(FI_EQ) { + INST(FI_EQ, 2, 1) { ARG_ANY(1); ARG_ANY(2); - res.type = T_BOOL; - res.val.i = val_same(v1, v2); + RESULT(T_BOOL, i, val_same(&v1, &v2)); } - INST(FI_LT) { + INST(FI_LT, 2, 1) { ARG_ANY(1); ARG_ANY(2); - i = val_compare(v1, v2); - if (i==CMP_ERROR) + int i = val_compare(&v1, &v2); + if (i == CMP_ERROR) runtime( "Can't compare values of incompatible types" ); - res.type = T_BOOL; - res.val.i = (i == -1); + RESULT(T_BOOL, i, (i == -1)); } - INST(FI_LTE) { + INST(FI_LTE, 2, 1) { ARG_ANY(1); ARG_ANY(2); - i = val_compare(v1, v2); - if (i==CMP_ERROR) + int i = val_compare(&v1, &v2); + if (i == CMP_ERROR) runtime( "Can't compare values of incompatible types" ); - res.type = T_BOOL; - res.val.i = (i != 1); + RESULT(T_BOOL, i, (i != 1)); } - INST(FI_NOT) { - ARG_T(1,0,T_BOOL); - res.val.i = !res.val.i; + INST(FI_NOT, 1, 1) { + ARG(1,T_BOOL); + RESULT(T_BOOL, i, !v1.val.i); } - INST(FI_MATCH) { + INST(FI_MATCH, 2, 1) { ARG_ANY(1); ARG_ANY(2); - res.type = T_BOOL; - res.val.i = val_in_range(v1, v2); - if (res.val.i == CMP_ERROR) + int i = val_in_range(&v1, &v2); + if (i == CMP_ERROR) runtime( "~ applied on unknown type pair" ); - res.val.i = !!res.val.i; + RESULT(T_BOOL, i, !!i); } - INST(FI_NOT_MATCH) { + INST(FI_NOT_MATCH, 2, 1) { ARG_ANY(1); ARG_ANY(2); - res.type = T_BOOL; - res.val.i = val_in_range(v1, v2); + int i = val_in_range(&v1, &v2); if (res.val.i == CMP_ERROR) runtime( "!~ applied on unknown type pair" ); - res.val.i = !res.val.i; + RESULT(T_BOOL, i, !i); } - INST(FI_DEFINED) { + INST(FI_DEFINED, 1, 1) { ARG_ANY(1); - res.type = T_BOOL; - res.val.i = (v1.type != T_VOID) && !undef_value(v1); + RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1)); } - INST(FI_TYPE) { + + INST(FI_TYPE, 1, 1) { ARG_ANY(1); /* There may be more types supporting this operation */ switch (v1.type) { case T_NET: - res.type = T_ENUM_NETTYPE; - res.val.i = v1.val.net->type; + RESULT(T_ENUM_NETTYPE, i, v1.val.net->type); break; default: runtime( "Can't determine type of this item" ); } } - INST(FI_IS_V4) { + + INST(FI_IS_V4, 1, 1) { ARG(1, T_IP); - res.type = T_BOOL; - res.val.i = ipa_is_ip4(v1.val.ip); + RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip)); } - /* Set to indirect value, a[0] = variable, a[1] = value */ - INST(FI_SET) { + /* Set to indirect value prepared in v1 */ + INST(FI_SET, 1, 0) { ARG_ANY(2); - sym = what->a[0].p; - vp = sym->def; - if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) + SYMBOL(1); + 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(v2)) + if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1)) { - vp->type = T_QUAD; - vp->val.i = ipa_to_u32(v2.val.ip); + *((struct f_val *) sym->def) = (struct f_val) { + .type = T_QUAD, + .val.i = ipa_to_u32(v1.val.ip), + }; break; } runtime( "Assigning to variable of incompatible type" ); } - *vp = v2; + *((struct f_val *) sym->def) = v1; } /* some constants have value in a[1], some in *a[0].p, strange. */ - INST(FI_CONSTANT) { /* integer (or simple type) constant, string, set, or prefix_set */ - res = what->val; + INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */ + VALI; // res = what->val; + RESULT_OK; } - INST(FI_VARIABLE) { - res = * ((struct f_val *) what->a[0].p); + INST(FI_VARIABLE, 0, 1) { + VALP(1); // res = * ((struct f_val *) what->a[0].p); + SAME([[if (strcmp(f1->sym->name, f2->sym->name)) return 0; ]]); + RESULT_OK; } - INST(FI_CONSTANT_INDIRECT) { - res = * ((struct f_val *) what->a[0].p); + INST(FI_CONSTANT_INDIRECT, 0, 1) { + VALP(1); + SAME([[if (!val_same(f1->vp, f2->vp)) return 0; ]]); + RESULT_OK; } - INST(FI_PRINT) { + INST(FI_PRINT, 1, 0) { ARG_ANY(1); - val_format(v1, &fs->buf); + val_format(&(v1), &fs->buf); } - INST(FI_CONDITION) { - ARG_T(1, 0, T_BOOL); + INST(FI_CONDITION, 1, 0) { + ARG(1, T_BOOL); if (res.val.i) - ARG_ANY_T(2,0); + LINE(2,0); else - ARG_ANY_T(3,0); + LINE(3,1); } - INST(FI_PRINT_AND_DIE) { - ARG_ANY(1); - if ((what->a[1].i == F_NOP || (what->a[1].i != F_NONL && what->a[0].p)) && + INST(FI_PRINT_AND_DIE, 0, 0) { + POSTFIXIFY([[ + if (what->a[0].p) { + pos = postfixify(dest, what->a[0].p, pos); + dest->items[pos].flags |= FIF_PRINTED; + } + ]]); + LINE_SIZE([[ + if (what->a[0].p) { + cnt += inst_line_size(what->a[0].p); + } + ]]); + + FRET(2); + + if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) && !(fs->flags & FF_SILENT)) log_commit(*L_INFO, &fs->buf); - switch (what->a[1].i) { + switch (fret) { case F_QUITBIRD: die( "Filter asked me to die" ); 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 */ - return what->a[1].i; /* We have to return now, no more processing. */ + return fret; /* We have to return now, no more processing. */ case F_NONL: case F_NOP: break; @@ -280,40 +293,43 @@ bug( "unknown return type: Can't happen"); } } - INST(FI_RTA_GET) { /* rta access */ + + INST(FI_RTA_GET, 0, 1) { /* rta access */ { + STATIC_ATTR; ACCESS_RTE; struct rta *rta = (*fs->rte)->attrs; - res.type = what->aux; - switch (what->a[1].i) + switch (sa.sa_code) { - case SA_FROM: res.val.ip = rta->from; break; - case SA_GW: res.val.ip = rta->nh.gw; break; - case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break; - case SA_PROTO: res.val.s = rta->src->proto->name; break; - case SA_SOURCE: res.val.i = rta->source; break; - case SA_SCOPE: res.val.i = rta->scope; break; - case SA_DEST: res.val.i = rta->dest; break; - case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break; - case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break; + case SA_FROM: RESULT(sa.f_type, ip, rta->from); break; + case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break; + case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break; + case SA_PROTO: RESULT(sa.f_type, s, rta->src->proto->name); break; + case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break; + case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break; + case SA_DEST: RESULT(sa.f_type, i, rta->dest); break; + case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break; + case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break; default: - bug("Invalid static attribute access (%x)", res.type); + bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); } } } - INST(FI_RTA_SET) { + + INST(FI_RTA_SET, 1, 0) { + STATIC_ATTR; ACCESS_RTE; ARG_ANY(1); - if (what->aux != v1.type) + if (sa.f_type != v1.type) runtime( "Attempt to set static attribute to incompatible type" ); f_rta_cow(fs); { struct rta *rta = (*fs->rte)->attrs; - switch (what->a[1].i) + switch (sa.sa_code) { case SA_FROM: rta->from = v1.val.ip; @@ -339,15 +355,17 @@ break; case SA_DEST: - i = v1.val.i; - if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) - runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + { + int i = v1.val.i; + if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) + runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); - rta->dest = i; - rta->nh.gw = IPA_NONE; - rta->nh.iface = NULL; - rta->nh.next = NULL; - rta->hostentry = NULL; + rta->dest = i; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; + rta->hostentry = NULL; + } break; case SA_IFNAME: @@ -365,124 +383,112 @@ break; default: - bug("Invalid static attribute access (%x)", res.type); + bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); } } } - INST(FI_EA_GET) { /* Access to extended attributes */ + + INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */ + DYNAMIC_ATTR; ACCESS_RTE; ACCESS_EATTRS; { - u16 code = what->a[1].i; - int f_type = what->aux >> 8; - eattr *e = ea_find(*fs->eattrs, code); + eattr *e = ea_find(*fs->eattrs, da.ea_code); if (!e) { /* A special case: undefined as_path looks like empty as_path */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) { - res.type = T_PATH; - res.val.ad = &undef_adata; + if (da.type == EAF_TYPE_AS_PATH) { + RESULT(T_PATH, ad, &null_adata); break; } /* The same special case for int_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) { - res.type = T_CLIST; - res.val.ad = &undef_adata; + if (da.type == EAF_TYPE_INT_SET) { + RESULT(T_CLIST, ad, &null_adata); break; } /* The same special case for ec_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { - res.type = T_ECLIST; - res.val.ad = &undef_adata; + if (da.type == EAF_TYPE_EC_SET) { + RESULT(T_ECLIST, ad, &null_adata); break; } /* The same special case for lc_set */ - if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) { - res.type = T_LCLIST; - res.val.ad = &undef_adata; + if (da.type == EAF_TYPE_LC_SET) { + RESULT(T_LCLIST, ad, &null_adata); break; } /* Undefined value */ res.type = T_VOID; + RESULT_OK; break; } switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: - res.type = f_type; - res.val.i = e->u.data; + RESULT(da.f_type, i, e->u.data); break; case EAF_TYPE_ROUTER_ID: - res.type = T_QUAD; - res.val.i = e->u.data; + RESULT(T_QUAD, i, e->u.data); break; case EAF_TYPE_OPAQUE: - res.type = T_ENUM_EMPTY; - res.val.i = 0; + RESULT(T_ENUM_EMPTY, i, 0); break; case EAF_TYPE_IP_ADDRESS: - res.type = T_IP; - struct adata * ad = e->u.ptr; - res.val.ip = * (ip_addr *) ad->data; + RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data)); break; case EAF_TYPE_AS_PATH: - res.type = T_PATH; - res.val.ad = e->u.ptr; + RESULT(T_PATH, ad, e->u.ptr); break; case EAF_TYPE_BITFIELD: - res.type = T_BOOL; - res.val.i = !!(e->u.data & BITFIELD_MASK(what)); + RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit))); break; case EAF_TYPE_INT_SET: - res.type = T_CLIST; - res.val.ad = e->u.ptr; + RESULT(T_CLIST, ad, e->u.ptr); break; case EAF_TYPE_EC_SET: - res.type = T_ECLIST; - res.val.ad = e->u.ptr; + RESULT(T_ECLIST, ad, e->u.ptr); break; case EAF_TYPE_LC_SET: - res.type = T_LCLIST; - res.val.ad = e->u.ptr; + RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: res.type = T_VOID; + RESULT_OK; break; default: - bug("Unknown type in e,a"); + bug("Unknown dynamic attribute type"); } } } - INST(FI_EA_SET) { + + INST(FI_EA_SET, 1, 0) { + DYNAMIC_ATTR; ACCESS_RTE; ACCESS_EATTRS; ARG_ANY(1); { struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - u16 code = what->a[1].i; - int f_type = what->aux >> 8; l->next = NULL; l->flags = EALF_SORTED; l->count = 1; - l->attrs[0].id = code; + l->attrs[0].id = da.ea_code; l->attrs[0].flags = 0; - l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH; + l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; - switch (what->aux & EAF_TYPE_MASK) { + switch (da.type) { case EAF_TYPE_INT: - if (v1.type != f_type) + 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)) { + if (val_is_ip4(&v1)) { l->attrs[0].u.data = ipa_to_u32(v1.val.ip); break; } @@ -514,13 +520,13 @@ runtime( "Setting bit in bitfield attribute to non-bool value" ); { /* First, we have to find the old value */ - eattr *e = ea_find(*fs->eattrs, code); + eattr *e = ea_find(*fs->eattrs, da.ea_code); u32 data = e ? e->u.data : 0; if (v1.val.i) - l->attrs[0].u.data = data | BITFIELD_MASK(what); + l->attrs[0].u.data = data | (1u << da.bit); else - l->attrs[0].u.data = data & ~BITFIELD_MASK(what);; + l->attrs[0].u.data = data & ~(1u << da.bit); } break; case EAF_TYPE_INT_SET: @@ -551,12 +557,13 @@ *fs->eattrs = l; } } - INST(FI_PREF_GET) { + + INST(FI_PREF_GET, 0, 1) { ACCESS_RTE; - res.type = T_INT; - res.val.i = (*fs->rte)->pref; + RESULT(T_INT, i, (*fs->rte)->pref); } - INST(FI_PREF_SET) { + + INST(FI_PREF_SET, 1, 0) { ACCESS_RTE; ARG(1,T_INT); if (v1.val.i > 0xFFFF) @@ -564,149 +571,221 @@ f_rte_cow(fs); (*fs->rte)->pref = v1.val.i; } - INST(FI_LENGTH) { /* Get length of */ + + INST(FI_LENGTH, 1, 1) { /* Get length of */ ARG_ANY(1); - res.type = T_INT; switch(v1.type) { - case T_NET: res.val.i = net_pxlen(v1.val.net); break; - case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; - case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break; - case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break; - case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break; + case T_NET: RESULT(T_INT, i, net_pxlen(v1.val.net)); break; + case T_PATH: RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break; + case T_CLIST: RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break; + case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break; + case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break; default: runtime( "Prefix, path, clist or eclist expected" ); } } - INST(FI_SADR_SRC) { /* Get SADR src prefix */ + + INST(FI_SADR_SRC, 1, 1) { /* Get SADR 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 *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); - net_fill_ip6(src, net->src_prefix, net->src_pxlen); + net_addr_ip6_sadr *net = (void *) v1.val.net; + net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); + net_fill_ip6(src, net->src_prefix, net->src_pxlen); - res.type = T_NET; - res.val.net = src; - } + RESULT(T_NET, net, src); } - INST(FI_ROA_MAXLEN) { /* Get ROA max prefix length */ + + INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */ ARG(1, T_NET); if (!net_is_roa(v1.val.net)) runtime( "ROA expected" ); - res.type = T_INT; - res.val.i = (v1.val.net->type == NET_ROA4) ? + RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ? ((net_addr_roa4 *) v1.val.net)->max_pxlen : - ((net_addr_roa6 *) v1.val.net)->max_pxlen; + ((net_addr_roa6 *) v1.val.net)->max_pxlen); } - INST(FI_ROA_ASN) { /* Get ROA ASN */ + + INST(FI_ROA_ASN, 1, 1) { /* Get ROA ASN */ ARG(1, T_NET); if (!net_is_roa(v1.val.net)) runtime( "ROA expected" ); - res.type = T_INT; - res.val.i = (v1.val.net->type == NET_ROA4) ? + RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ? ((net_addr_roa4 *) v1.val.net)->asn : - ((net_addr_roa6 *) v1.val.net)->asn; + ((net_addr_roa6 *) v1.val.net)->asn); } - INST(FI_IP) { /* Convert prefix to ... */ + + INST(FI_IP, 1, 1) { /* Convert prefix to ... */ ARG(1, T_NET); - res.type = T_IP; - res.val.ip = net_prefix(v1.val.net); + RESULT(T_IP, ip, net_prefix(v1.val.net)); } - INST(FI_ROUTE_DISTINGUISHER) { + + INST(FI_ROUTE_DISTINGUISHER, 1, 1) { ARG(1, T_NET); if (!net_is_vpn(v1.val.net)) runtime( "VPN address expected" ); - res.type = T_RD; - res.val.ec = net_rd(v1.val.net); + RESULT(T_RD, ec, net_rd(v1.val.net)); } - INST(FI_AS_PATH_FIRST) { /* Get first ASN from AS PATH */ - ARG(1, T_PATH); - as = 0; + INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */ + ARG(1, T_PATH); + int as = 0; as_path_get_first(v1.val.ad, &as); - res.type = T_INT; - res.val.i = as; + RESULT(T_INT, i, as); } - INST(FI_AS_PATH_LAST) { /* Get last ASN from AS PATH */ - ARG(1, T_PATH); - as = 0; + INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */ + ARG(1, T_PATH); + int as = 0; as_path_get_last(v1.val.ad, &as); - res.type = T_INT; - res.val.i = as; + RESULT(T_INT, i, as); } - INST(FI_AS_PATH_LAST_NAG) { /* Get last ASN from non-aggregated part of AS PATH */ - ARG(1, T_PATH); - res.type = T_INT; - res.val.i = as_path_get_last_nonaggregated(v1.val.ad); + INST(FI_AS_PATH_LAST_NAG, 1, 1) { /* Get last ASN from non-aggregated part of AS PATH */ + ARG(1, T_PATH); + RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad)); } - INST(FI_RETURN) { - ARG_ANY_T(1,0); - return F_RETURN; + + INST(FI_RETURN, 1, 1) { + /* Acquire the return value */ + ARG_ANY(1); + uint retpos = vstk.cnt; + + /* Drop every sub-block including ourselves */ + while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN)) + ; + + /* Now we are at the caller frame; if no such, try to convert to accept/reject. */ + if (!estk.cnt) + if (vstk.val[retpos].type == T_BOOL) + if (vstk.val[retpos].val.i) + return F_ACCEPT; + else + return F_REJECT; + else + runtime("Can't return non-bool from non-function"); + + /* Set the value stack position */ + vstk.cnt = estk.item[estk.cnt].ventry; + + /* Copy the return value */ + RESULT_VAL(vstk.val[retpos]); } - INST(FI_CALL) { - ARG_ANY_T(1,0); - fret = interpret(fs, what->a[1].p); - if (fret > F_RETURN) - return fret; + + INST(FI_CALL, 0, 1) { + /* First push the code */ + LINEP(2,0); + curline.emask |= FE_RETURN; + + /* Then push the arguments */ + LINE(1,1); } - INST(FI_CLEAR_LOCAL_VARS) { /* Clear local variables */ - for (sym = what->a[0].p; sym != NULL; sym = sym->aux2) + + INST(FI_DROP_RESULT, 1, 0) { + ARG_ANY(1); + } + + INST(FI_CLEAR_LOCAL_VARS, 0, 0) { /* Clear local variables */ + SYMBOL(1); + for ( ; sym != NULL; sym = sym->aux2) ((struct f_val *) sym->def)->type = T_VOID; } - INST(FI_SWITCH) { + INST(FI_SWITCH, 1, 0) { ARG_ANY(1); - { - struct f_tree *t = find_tree(what->a[1].p, v1); + POSTFIXIFY([[ + dest->items[pos].tree = what->a[1].p; + ]]); + const struct f_tree *t = find_tree(what->tree, &v1); + if (!t) { + v1.type = T_VOID; + t = find_tree(what->tree, &v1); if (!t) { - v1.type = T_VOID; - t = find_tree(what->a[1].p, v1); - if (!t) { - debug( "No else statement?\n"); - break; - } + debug( "No else statement?\n"); + break; } - /* It is actually possible to have t->data NULL */ - - fret = interpret(fs, t->data); - if (fret >= F_RETURN) - return fret; } + /* It is actually possible to have t->data NULL */ + + LINEX(t->data); } - INST(FI_IP_MASK) { /* IP.MASK(val) */ + + INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */ ARG(1, T_IP); ARG(2, T_INT); - - res.type = T_IP; - res.val.ip = ipa_is_ip4(v1.val.ip) ? + RESULT(T_IP, 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))); + ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]); } - INST(FI_EMPTY) { /* Create empty attribute */ - res.type = what->aux; - res.val.ad = adata_empty(fs->pool, 0); - } - INST(FI_PATH_PREPEND) { /* Path prepend */ + INST(FI_PATH_PREPEND, 2, 1) { /* Path prepend */ ARG(1, T_PATH); ARG(2, T_INT); - - res.type = T_PATH; - res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); + RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]); } - INST(FI_CLIST_ADD_DEL) { /* (Extended) Community list add or delete */ + INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */ + ARG_ANY(1); + ARG_ANY(2); + if (v1.type == T_PATH) + runtime("Can't add to path"); + + else if (v1.type == T_CLIST) + { + /* Community (or cluster) list */ + struct f_val dummy; + + if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) + RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, v2.val.i) ]]); + /* IP->Quad implicit conversion */ + else if (val_is_ip4(&v2)) + RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, 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(fs->pool, v1.val.ad, v2.val.ad) ]]); + else + runtime("Can't add non-pair"); + } + + else if (v1.type == T_ECLIST) + { + /* v2.val is either EC or EC-set */ + 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(fs->pool, 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(fs->pool, 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)) + runtime("Can't add set"); + else if (v2.type == T_LCLIST) + RESULT(T_LCLIST, ad, [[ lc_set_union(fs->pool, 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(fs->pool, v1.val.ad, v2.val.lc) ]]); + + } + + else + runtime("Can't add to non-[e|l]clist"); + } + + INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */ ARG_ANY(1); ARG_ANY(2); if (v1.type == T_PATH) { - struct f_tree *set = NULL; + const struct f_tree *set = NULL; u32 key = 0; - int pos; if (v2.type == T_INT) key = v2.val.i; @@ -715,210 +794,154 @@ else runtime("Can't delete non-integer (set)"); - switch (what->aux) - { - case 'a': runtime("Can't add to path"); - case 'd': pos = 0; break; - case 'f': pos = 1; break; - default: bug("unknown Ca operation"); - } - - if (pos && !set) - runtime("Can't filter integer"); - - res.type = T_PATH; - res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos); + RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, set, key, 0) ]]); } + else if (v1.type == T_CLIST) { /* Community (or cluster) list */ struct f_val dummy; - int arg_set = 0; - uint n = 0; if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) - n = v2.val.i; + RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, v2.val.i) ]]); /* IP->Quad implicit conversion */ - else if (val_is_ip4(v2)) - n = ipa_to_u32(v2.val.ip); - else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy)) - arg_set = 1; - else if (v2.type == T_CLIST) - arg_set = 2; + else if (val_is_ip4(&v2)) + RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, 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(fs->pool, v1.val.ad, &v2, 0) ]]); else - runtime("Can't add/delete non-pair"); - - res.type = T_CLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = int_set_add(fs->pool, v1.val.ad, n); - else - res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = int_set_del(fs->pool, v1.val.ad, n); - else - res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter pair"); - res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } + runtime("Can't delete non-pair"); } + else if (v1.type == T_ECLIST) { - /* Extended community list */ - int arg_set = 0; - /* v2.val is either EC or EC-set */ - if ((v2.type == T_SET) && eclist_set_type(v2.val.t)) - arg_set = 1; - else if (v2.type == T_ECLIST) - arg_set = 2; + if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST)) + RESULT(T_ECLIST, ad, [[ eclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]); else if (v2.type != T_EC) - runtime("Can't add/delete non-ec"); - - res.type = T_ECLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec); - else - res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec); - else - res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter ec"); - res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } + runtime("Can't delete non-ec"); + else + RESULT(T_ECLIST, ad, [[ ec_set_del(fs->pool, v1.val.ad, v2.val.ec) ]]); } + else if (v1.type == T_LCLIST) { - /* Large community list */ - int arg_set = 0; - /* v2.val is either LC or LC-set */ - if ((v2.type == T_SET) && lclist_set_type(v2.val.t)) - arg_set = 1; - else if (v2.type == T_LCLIST) - arg_set = 2; + if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST)) + RESULT(T_LCLIST, ad, [[ lclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]); else if (v2.type != T_LC) - runtime("Can't add/delete non-lc"); - - res.type = T_LCLIST; - switch (what->aux) - { - case 'a': - if (arg_set == 1) - runtime("Can't add set"); - else if (!arg_set) - res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc); - else - res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad); - break; - - case 'd': - if (!arg_set) - res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc); - else - res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0); - break; - - case 'f': - if (!arg_set) - runtime("Can't filter lc"); - res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } + runtime("Can't delete non-lc"); + else + RESULT(T_LCLIST, ad, [[ lc_set_del(fs->pool, v1.val.ad, v2.val.lc) ]]); } - else - runtime("Can't add/delete to non-[e|l]clist"); + else + runtime("Can't delete in non-[e|l]clist"); } - INST(FI_ROA_CHECK) { /* ROA Check */ - if (what->arg1) + INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */ + ARG_ANY(1); + ARG_ANY(2); + if (v1.type == T_PATH) { - ARG(1, T_NET); - ARG(2, T_INT); + u32 key = 0; - as = v2.val.i; + if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT)) + RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, v2.val.t, key, 1) ]]); + else + runtime("Can't filter integer"); } + + else if (v1.type == T_CLIST) + { + /* Community (or cluster) list */ + 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(fs->pool, v1.val.ad, &v2, 1) ]]); + else + runtime("Can't filter pair"); + } + + else if (v1.type == T_ECLIST) + { + /* 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(fs->pool, v1.val.ad, &v2, 1) ]]); + else + runtime("Can't filter 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(fs->pool, v1.val.ad, &v2, 1) ]]); + else + runtime("Can't filter lc"); + } + else - { - ACCESS_RTE; - ACCESS_EATTRS; - v1.val.net = (*fs->rte)->net->n.addr; + runtime("Can't filter non-[e|l]clist"); + } - /* 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)); + INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */ + RTC(1); + ACCESS_RTE; + ACCESS_EATTRS; + const net_addr *net = (*fs->rte)->net->n.addr; - if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH)) - runtime("Missing AS_PATH attribute"); + /* 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)); - as_path_get_last(e->u.ptr, &as); - } + 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); - struct rtable *table = what->a[2].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; + 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 */ + ARG(1, T_NET); + ARG(2, T_INT); + RTC(3); + + u32 as = v2.val.i; + + 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 != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6)) - res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */ + RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */ else - res.val.i = net_roa_check(table, v1.val.net, as); + RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, v1.val.net, as) ]]); } - INST(FI_FORMAT) { /* Format */ + INST(FI_FORMAT, 1, 0) { /* Format */ ARG_ANY(1); - - res.type = T_STRING; - res.val.s = val_format_str(fs, v1); + RESULT(T_STRING, s, val_format_str(fs, &v1)); } - INST(FI_ASSERT) { /* Birdtest Assert */ + INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ ARG(1, T_BOOL); - - res.type = v1.type; - res.val = v1.val; - + POSTFIXIFY([[ + dest->items[pos].s = what->a[1].p; + ]]); CALL(bt_assert_hook, res.val.i, what); } - diff --git a/filter/f-util.c b/filter/f-util.c index 11a5e97e..4f11a6d9 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -30,8 +30,7 @@ struct f_inst * f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da) { struct f_inst *ret = f_new_inst(fi_code); - ret->aux = (da.f_type << 8) | da.type; - ret->a[1].i = da.ea_code; + ret->da = da; return ret; } @@ -39,9 +38,7 @@ 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->a[1].i = sa.sa_code; - ret->a[0].i = sa.readonly; + ret->sa = sa; return ret; } @@ -49,13 +46,12 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa) * Generate set_dynamic( operation( get_dynamic(), argument ) ) */ struct f_inst * -f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument) +f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument) { struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da), - *oper = f_new_inst(operation), + *oper = f_new_inst(fi_code), *get_dyn = f_new_inst_da(FI_EA_GET, da); - oper->aux = operation_aux; oper->a[0].p = get_dyn; oper->a[1].p = argument; @@ -63,21 +59,6 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s return set_dyn; } -struct f_inst * -f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) -{ - struct f_inst *ret = f_new_inst(FI_ROA_CHECK); - ret->arg1 = prefix; - ret->arg2 = asn; - /* prefix == NULL <-> asn == NULL */ - - if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) - cf_error("%s is not a ROA table", table->name); - ret->arg3 = table; - - return ret; -} - static const char * const f_instruction_name_str[] = { #define F(c,a,b) \ [c] = #c, @@ -219,7 +200,7 @@ ca_lookup(pool *p, const char *name, int f_type) } cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1); - cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id)); + cas->fda = f_new_dynamic_attr(ea_type, 0, f_type, EA_CUSTOM(id)); cas->uc = 1; strcpy(cas->name, name); diff --git a/filter/filter.c b/filter/filter.c index 308792b9..858d5fc5 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -50,15 +50,6 @@ #define CMP_ERROR 999 -#define FILTER_STACK_DEPTH 16384 - -/* Filter interpreter stack. Make this thread local after going parallel. */ -struct filter_stack { - struct f_val val; -}; - -static struct filter_stack filter_stack[FILTER_STACK_DEPTH]; - /* Internal filter state, to be allocated on stack when executing filters */ struct filter_state { struct rte **rte; @@ -66,14 +57,10 @@ struct filter_state { struct ea_list **eattrs; struct linpool *pool; struct buffer buf; - struct filter_stack *stack; - int stack_ptr; int flags; }; -void (*bt_assert_hook)(int result, struct f_inst *assert); - -static struct adata undef_adata; /* adata of length 0 used for undefined */ +void (*bt_assert_hook)(int result, const struct f_line_item *assert); /* Special undef value for paths and clists */ static inline int @@ -81,9 +68,23 @@ 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); + (v.val.ad == &null_adata); } +const struct f_val f_const_empty_path = { + .type = T_PATH, + .val.ad = &null_adata, +}, f_const_empty_clist = { + .type = T_CLIST, + .val.ad = &null_adata, +}, f_const_empty_eclist = { + .type = T_ECLIST, + .val.ad = &null_adata, +}, f_const_empty_lclist = { + .type = T_LCLIST, + .val.ad = &null_adata, +}; + static struct adata * adata_empty(struct linpool *pool, int l) { @@ -93,16 +94,16 @@ adata_empty(struct linpool *pool, int l) } static void -pm_format(struct f_path_mask *p, buffer *buf) +pm_format(const struct f_path_mask *p, buffer *buf) { buffer_puts(buf, "[= "); - while (p) + for (uint i=0; ilen; i++) { - switch(p->kind) + switch(p->item[i].kind) { case PM_ASN: - buffer_print(buf, "%u ", p->val); + buffer_print(buf, "%u ", p->item[i].asn); break; case PM_QUESTION: @@ -114,21 +115,20 @@ pm_format(struct f_path_mask *p, buffer *buf) break; case PM_ASN_RANGE: - buffer_print(buf, "%u..%u ", p->val, p->val2); + buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to); break; case PM_ASN_EXPR: ASSERT(0); } - p = p->next; } buffer_puts(buf, "=]"); } -static inline int val_is_ip4(const struct f_val v) -{ return (v.type == T_IP) && ipa_is_ip4(v.val.ip); } +static inline int val_is_ip4(const struct f_val *v) +{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); } static inline int lcomm_cmp(lcomm v1, lcomm v2) @@ -152,25 +152,25 @@ lcomm_cmp(lcomm v1, lcomm v2) * that it can be used for building balanced trees. */ int -val_compare(struct f_val v1, struct f_val v2) +val_compare(const struct f_val *v1, const struct f_val *v2) { - if (v1.type != v2.type) { - if (v1.type == T_VOID) /* Hack for else */ + if (v1->type != v2->type) { + if (v1->type == T_VOID) /* Hack for else */ return -1; - if (v2.type == T_VOID) + if (v2->type == T_VOID) return 1; /* IP->Quad implicit conversion */ - if ((v1.type == T_QUAD) && val_is_ip4(v2)) - return uint_cmp(v1.val.i, ipa_to_u32(v2.val.ip)); - if (val_is_ip4(v1) && (v2.type == T_QUAD)) - return uint_cmp(ipa_to_u32(v1.val.ip), v2.val.i); + if ((v1->type == T_QUAD) && val_is_ip4(v2)) + return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip)); + if (val_is_ip4(v1) && (v2->type == T_QUAD)) + return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i); debug( "Types do not match in val_compare\n" ); return CMP_ERROR; } - switch (v1.type) { + switch (v1->type) { case T_VOID: return 0; case T_ENUM: @@ -178,47 +178,52 @@ val_compare(struct f_val v1, struct f_val v2) case T_BOOL: case T_PAIR: case T_QUAD: - return uint_cmp(v1.val.i, v2.val.i); + return uint_cmp(v1->val.i, v2->val.i); case T_EC: case T_RD: - return u64_cmp(v1.val.ec, v2.val.ec); + return u64_cmp(v1->val.ec, v2->val.ec); case T_LC: - return lcomm_cmp(v1.val.lc, v2.val.lc); + return lcomm_cmp(v1->val.lc, v2->val.lc); case T_IP: - return ipa_compare(v1.val.ip, v2.val.ip); + return ipa_compare(v1->val.ip, v2->val.ip); case T_NET: - return net_compare(v1.val.net, v2.val.net); + return net_compare(v1->val.net, v2->val.net); case T_STRING: - return strcmp(v1.val.s, v2.val.s); + return strcmp(v1->val.s, v2->val.s); default: return CMP_ERROR; } } static int -pm_same(struct f_path_mask *m1, struct f_path_mask *m2) +pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2) { - while (m1 && m2) + if (m1->len != m2->len) + + for (uint i=0; ilen; i++) { - if (m1->kind != m2->kind) + if (m1->item[i].kind != m2->item[i].kind) return 0; - if (m1->kind == PM_ASN_EXPR) - { - if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val)) - return 0; + switch (m1->item[i].kind) { + case PM_ASN: + if (m1->item[i].asn != m2->item[i].asn) + return 0; + break; + case PM_ASN_EXPR: + if (!f_same(m1->item[i].expr, m2->item[i].expr)) + return 0; + break; + case PM_ASN_RANGE: + if (m1->item[i].from != m2->item[i].from) + return 0; + if (m1->item[i].to != m2->item[i].to) + return 0; + break; } - else - { - if ((m1->val != m2->val) || (m1->val2 != m2->val2)) - return 0; - } - - m1 = m1->next; - m2 = m2->next; } - return !m1 && !m2; + return 1; } /** @@ -230,7 +235,7 @@ pm_same(struct f_path_mask *m1, struct f_path_mask *m2) * Comparison of values of different types is valid and returns 0. */ int -val_same(struct f_val v1, struct f_val v2) +val_same(const struct f_val *v1, const struct f_val *v2) { int rc; @@ -238,28 +243,28 @@ val_same(struct f_val v1, struct f_val v2) if (rc != CMP_ERROR) return !rc; - if (v1.type != v2.type) + if (v1->type != v2->type) return 0; - switch (v1.type) { + switch (v1->type) { case T_PATH_MASK: - return pm_same(v1.val.path_mask, v2.val.path_mask); + return pm_same(v1->val.path_mask, v2->val.path_mask); case T_PATH: case T_CLIST: case T_ECLIST: case T_LCLIST: - return adata_same(v1.val.ad, v2.val.ad); + return adata_same(v1->val.ad, v2->val.ad); case T_SET: - return same_tree(v1.val.t, v2.val.t); + return same_tree(v1->val.t, v2->val.t); case T_PREFIX_SET: - return trie_same(v1.val.ti, v2.val.ti); + return trie_same(v1->val.ti, v2->val.ti); default: - bug("Invalid type in val_same(): %x", v1.type); + bug("Invalid type in val_same(): %x", v1->type); } } static int -clist_set_type(struct f_tree *set, struct f_val *v) +clist_set_type(const struct f_tree *set, struct f_val *v) { switch (set->from.type) { @@ -272,7 +277,7 @@ clist_set_type(struct f_tree *set, struct f_val *v) return 1; case T_IP: - if (val_is_ip4(set->from) && val_is_ip4(set->to)) + if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to))) { v->type = T_QUAD; return 1; @@ -285,15 +290,15 @@ clist_set_type(struct f_tree *set, struct f_val *v) } static inline int -eclist_set_type(struct f_tree *set) +eclist_set_type(const struct f_tree *set) { return set->from.type == T_EC; } static inline int -lclist_set_type(struct f_tree *set) +lclist_set_type(const struct f_tree *set) { return set->from.type == T_LC; } static int -clist_match_set(struct adata *clist, struct f_tree *set) +clist_match_set(const struct adata *clist, const struct f_tree *set) { if (!clist) return 0; @@ -307,14 +312,14 @@ clist_match_set(struct adata *clist, struct f_tree *set) while (l < end) { v.val.i = *l++; - if (find_tree(set, v)) + if (find_tree(set, &v)) return 1; } return 0; } static int -eclist_match_set(struct adata *list, struct f_tree *set) +eclist_match_set(const struct adata *list, const struct f_tree *set) { if (!list) return 0; @@ -330,7 +335,7 @@ eclist_match_set(struct adata *list, struct f_tree *set) v.type = T_EC; for (i = 0; i < len; i += 2) { v.val.ec = ec_get(l, i); - if (find_tree(set, v)) + if (find_tree(set, &v)) return 1; } @@ -338,7 +343,7 @@ eclist_match_set(struct adata *list, struct f_tree *set) } static int -lclist_match_set(struct adata *list, struct f_tree *set) +lclist_match_set(const struct adata *list, const struct f_tree *set) { if (!list) return 0; @@ -354,23 +359,23 @@ lclist_match_set(struct adata *list, struct f_tree *set) v.type = T_LC; for (i = 0; i < len; i += 3) { v.val.lc = lc_get(l, i); - if (find_tree(set, v)) + if (find_tree(set, &v)) return 1; } return 0; } -static struct adata * -clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) +static const struct adata * +clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) { if (!list) return NULL; - int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ struct f_val v; if (tree) - clist_set_type(set.val.t, &v); + clist_set_type(set->val.t, &v); else v.type = T_PAIR; @@ -383,7 +388,7 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos while (l < end) { v.val.i = *l++; /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos) + if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos) *k++ = v.val.i; } @@ -396,13 +401,13 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos return res; } -static struct adata * -eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) +static const struct adata * +eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) { if (!list) return NULL; - int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ struct f_val v; int len = int_set_get_size(list); @@ -415,7 +420,7 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po for (i = 0; i < len; i += 2) { v.val.ec = ec_get(l, i); /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) { + if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) { *k++ = l[i]; *k++ = l[i+1]; } @@ -430,13 +435,13 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po return res; } -static struct adata * -lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) +static const struct adata * +lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) { if (!list) return NULL; - int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ struct f_val v; int len = int_set_get_size(list); @@ -449,7 +454,7 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po for (i = 0; i < len; i += 3) { v.val.lc = lc_get(l, i); /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos) + if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos) k = lc_copy(k, l+i); } @@ -470,57 +475,57 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po * Checks if @v1 is element (|~| operator) of @v2. */ static int -val_in_range(struct f_val v1, struct f_val v2) +val_in_range(const struct f_val *v1, const struct f_val *v2) { - if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) - return as_path_match(v1.val.ad, v2.val.path_mask); + if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK)) + return as_path_match(v1->val.ad, v2->val.path_mask); - if ((v1.type == T_INT) && (v2.type == T_PATH)) - return as_path_contains(v2.val.ad, v1.val.i, 1); + if ((v1->type == T_INT) && (v2->type == T_PATH)) + return as_path_contains(v2->val.ad, v1->val.i, 1); - if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) - return int_set_contains(v2.val.ad, v1.val.i); + if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST)) + return int_set_contains(v2->val.ad, v1->val.i); /* IP->Quad implicit conversion */ - if (val_is_ip4(v1) && (v2.type == T_CLIST)) - return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip)); + 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); + if ((v1->type == T_EC) && (v2->type == T_ECLIST)) + return ec_set_contains(v2->val.ad, v1->val.ec); - if ((v1.type == T_LC) && (v2.type == T_LCLIST)) - return lc_set_contains(v2.val.ad, v1.val.lc); + if ((v1->type == T_LC) && (v2->type == T_LCLIST)) + return lc_set_contains(v2->val.ad, v1->val.lc); - if ((v1.type == T_STRING) && (v2.type == T_STRING)) - return patmatch(v2.val.s, v1.val.s); + if ((v1->type == T_STRING) && (v2->type == T_STRING)) + return patmatch(v2->val.s, v1->val.s); - if ((v1.type == T_IP) && (v2.type == T_NET)) - return ipa_in_netX(v1.val.ip, v2.val.net); + if ((v1->type == T_IP) && (v2->type == T_NET)) + return ipa_in_netX(v1->val.ip, v2->val.net); - if ((v1.type == T_NET) && (v2.type == T_NET)) - return net_in_netX(v1.val.net, v2.val.net); + if ((v1->type == T_NET) && (v2->type == T_NET)) + return net_in_netX(v1->val.net, v2->val.net); - if ((v1.type == T_NET) && (v2.type == T_PREFIX_SET)) - return trie_match_net(v2.val.ti, v1.val.net); + if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET)) + return trie_match_net(v2->val.ti, v1->val.net); - if (v2.type != T_SET) + if (v2->type != T_SET) return CMP_ERROR; /* With integrated Quad<->IP implicit conversion */ - if ((v1.type == v2.val.t->from.type) || - ((v1.type == T_QUAD) && val_is_ip4(v2.val.t->from) && val_is_ip4(v2.val.t->to))) - return !!find_tree(v2.val.t, v1); + if ((v1->type == v2->val.t->from.type) || + ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to)))) + return !!find_tree(v2->val.t, v1); - if (v1.type == T_CLIST) - return clist_match_set(v1.val.ad, v2.val.t); + if (v1->type == T_CLIST) + return clist_match_set(v1->val.ad, v2->val.t); - if (v1.type == T_ECLIST) - return eclist_match_set(v1.val.ad, v2.val.t); + if (v1->type == T_ECLIST) + return eclist_match_set(v1->val.ad, v2->val.t); - if (v1.type == T_LCLIST) - return lclist_match_set(v1.val.ad, v2.val.t); + if (v1->type == T_LCLIST) + return lclist_match_set(v1->val.ad, v2->val.t); - if (v1.type == T_PATH) - return as_path_match_set(v1.val.ad, v2.val.t); + if (v1->type == T_PATH) + return as_path_match_set(v1->val.ad, v2->val.t); return CMP_ERROR; } @@ -529,31 +534,31 @@ val_in_range(struct f_val v1, struct f_val v2) * val_format - format filter value */ void -val_format(struct f_val v, buffer *buf) +val_format(const struct f_val *v, buffer *buf) { char buf2[1024]; - switch (v.type) + switch (v->type) { case T_VOID: buffer_puts(buf, "(void)"); return; - case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return; - case T_INT: buffer_print(buf, "%u", v.val.i); return; - case T_STRING: buffer_print(buf, "%s", v.val.s); return; - case T_IP: buffer_print(buf, "%I", v.val.ip); return; - case T_NET: buffer_print(buf, "%N", v.val.net); return; - case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return; - case T_QUAD: buffer_print(buf, "%R", v.val.i); return; - case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return; - case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return; - case T_RD: rd_format(v.val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return; - case T_PREFIX_SET: trie_format(v.val.ti, buf); return; - case T_SET: tree_format(v.val.t, buf); return; - case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return; - case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; - case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; - case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; - case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return; - case T_PATH_MASK: pm_format(v.val.path_mask, buf); return; - default: buffer_print(buf, "[unknown type %x]", v.type); return; + case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return; + case T_INT: buffer_print(buf, "%u", v->val.i); return; + case T_STRING: buffer_print(buf, "%s", v->val.s); return; + case T_IP: buffer_print(buf, "%I", v->val.ip); return; + case T_NET: buffer_print(buf, "%N", v->val.net); return; + case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return; + case T_QUAD: buffer_print(buf, "%R", v->val.i); return; + case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return; + case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return; + case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return; + case T_PREFIX_SET: trie_format(v->val.ti, buf); return; + case T_SET: tree_format(v->val.t, buf); return; + case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return; + case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; + case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; + case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; + case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return; + case T_PATH_MASK: pm_format(v->val.path_mask, buf); return; + default: buffer_print(buf, "[unknown type %x]", v->type); return; } } @@ -599,7 +604,7 @@ f_rta_cow(struct filter_state *fs) } static char * -val_format_str(struct filter_state *fs, struct f_val v) { +val_format_str(struct filter_state *fs, struct f_val *v) { buffer b; LOG_BUFFER_INIT(b); val_format(v, &b); @@ -608,6 +613,98 @@ val_format_str(struct filter_state *fs, struct f_val v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; +static uint +inst_line_size(const struct f_inst *what) +{ + uint cnt = 0; + for ( ; what; what = what->next) { + switch (what->fi_code) { +#include "filter/f-inst-line-size.c" + } + } + return cnt; +} + +#if DEBUGGING +#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) +static const char f_dump_line_indent_str[] = " "; + +static char val_dump_buffer[1024]; + +static const char * +val_dump(const struct f_val *v) { + static buffer b = { + .start = val_dump_buffer, + .end = val_dump_buffer + 1024, + }; + b.pos = b.start; + val_format(v, &b); + return val_dump_buffer; +} + +static void f_dump_line(const struct f_line *dest, int indent); + +static void +f_dump_line_item(const struct f_line_item *item, int indent) +{ + debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); + switch (item->fi_code) { +#include "filter/f-inst-dump.c" + } +} + +static void +f_dump_line(const struct f_line *dest, int indent) +{ + if (!dest) { + debug("%sNo filter line (NULL)\n", INDENT); + return; + } + debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len); + for (uint i=0; ilen; i++) + f_dump_line_item(&dest->items[i], indent+1); + debug("%sFilter line %p dump done\n", INDENT, dest); +#undef INDENT +} +#else +#define f_dump_line(...) +#endif + +static uint +postfixify(struct f_line *dest, const struct f_inst *what, uint pos) +{ + for ( ; what; what = what->next) { + switch (what->fi_code) { +#include "filter/f-inst-postfixify.c" + } + pos++; + } + return pos; +} + +struct f_line * +f_postfixify_concat(struct f_inst *first, ...) +{ + va_list args; + va_list argd; + va_start(args, first); + va_copy(argd, args); + + uint len = 0; + for (struct f_inst *what = first; what; what = va_arg(args, struct f_inst *)) + len += inst_line_size(what); + + va_end(args); + + struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len); + + for (struct f_inst *what = first; what; what = va_arg(argd, struct f_inst *)) + out->len = postfixify(out, what, out->len); + + f_dump_line(out, 0); + return out; +} + /** * interpret * @fs: filter state @@ -624,26 +721,28 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; * TWOARGS macro to get both of them evaluated. */ static enum filter_return -interpret(struct filter_state *fs, struct f_inst *what) +interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) { - struct symbol *sym; - struct f_val *vp; - unsigned u1, u2; - enum filter_return fret; - int i; - u32 as; + struct f_val_stack vstk; + vstk.cnt = 0; -#define res fs->stack[fs->stack_ptr].val -#define v0 res -#define v1 fs->stack[fs->stack_ptr + 1].val -#define v2 fs->stack[fs->stack_ptr + 2].val -#define v3 fs->stack[fs->stack_ptr + 3].val + struct f_exec_stack estk; + estk.cnt = 1; + estk.item[0].line = line; + estk.item[0].pos = 0; - res = (struct f_val) { .type = T_VOID }; +#define curline estk.item[estk.cnt-1] - for ( ; what; what = what->next) { - res = (struct f_val) { .type = T_VOID }; - switch (what->fi_code) { + while (estk.cnt > 0) { + while (curline.pos < curline.line->len) { + const struct f_line_item *what = &(curline.line->items[curline.pos++]); + + + switch (what->fi_code) { +#define res vstk.val[vstk.cnt] +#define v1 vstk.val[vstk.cnt] +#define v2 vstk.val[vstk.cnt + 1] +#define v3 vstk.val[vstk.cnt + 2] #define runtime(fmt, ...) do { \ if (!(fs->flags & FF_SILENT)) \ @@ -651,84 +750,70 @@ interpret(struct filter_state *fs, struct f_inst *what) return F_ERROR; \ } while(0) -#define ARG_ANY_T(n, tt) INTERPRET(what->a[n-1].p, tt) -#define ARG_ANY(n) ARG_ANY_T(n, n) - -#define ARG_T(n,tt,t) do { \ - ARG_ANY_T(n,tt); \ - if (v##tt.type != t) \ - runtime("Argument %d of instruction %s must be of type %02x, got %02x", \ - n, f_instruction_name(what->fi_code), t, v##tt.type); \ -} while (0) - -#define ARG(n,t) ARG_T(n,n,t) - -#define INTERPRET(what_, n) do { \ - fs->stack_ptr += n; \ - fret = interpret(fs, what_); \ - fs->stack_ptr -= n; \ - if (fret == F_RETURN) \ - bug("This shall not happen"); \ - if (fret > F_RETURN) \ - return fret; \ -} while (0) - #define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) - #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) -#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i)) - - case FI_NOP: - bug("This shall not happen"); - #include "filter/f-inst-interpret.c" - - break; - default: - bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); - #undef res +#undef v1 +#undef v2 +#undef v3 #undef runtime -#undef ARG_ANY -#undef ARG -#undef INTERPRET #undef ACCESS_RTE #undef ACCESS_EATTRS + } } + estk.cnt--; + } + + switch (vstk.cnt) { + case 0: + if (val) { + log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack"); + return F_ERROR; + } + return F_NOP; + case 1: + if (val) { + *val = vstk.val[0]; + return F_NOP; + } + /* fallthrough */ + default: + log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt); + return F_ERROR; } - return F_NOP; } -#define ARG(n) \ - if (!i_same(f1->a[n-1].p, f2->a[n-1].p)) \ - return 0; - -#define ONEARG ARG(1); -#define TWOARGS ONEARG; ARG(2); -#define THREEARGS TWOARGS; ARG(3); - -#define A2_SAME if (f1->a[1].i != f2->a[1].i) return 0; - /* - * i_same - function that does real comparing of instruction trees, you should call filter_same from outside + * f_same - function that does real comparing of instruction trees, you should call filter_same from outside */ int -i_same(struct f_inst *f1, struct f_inst *f2) +f_same(const struct f_line *fl1, const struct f_line *fl2) { - if ((!!f1) != (!!f2)) - return 0; - if (!f1) + if ((!fl1) && (!fl2)) return 1; - if (f1->aux != f2->aux) + if ((!fl1) || (!fl2)) return 0; - if (f1->fi_code != f2->fi_code) + if (fl1->len != fl2->len) return 0; - if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ - return 1; + for (uint i=0; ilen; i++) { +#define f1 (&(fl1->items[i])) +#define f2 (&(fl2->items[i])) + if (f1->fi_code != f2->fi_code) + return 0; + if (f1->flags != f2->flags) + return 0; - switch(f1->fi_code) { + switch(f1->fi_code) { +#include "filter/f-inst-same.c" + } + } + return 1; +} + +#if 0 case FI_ADD: /* fall through */ case FI_SUBTRACT: case FI_MULTIPLY: @@ -842,9 +927,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) case FI_ASSERT: ONEARG; break; default: bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff); - } - return i_same(f1->next, f2->next); -} +#endif /** * f_run - run a filter for a route @@ -871,7 +954,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) * modified in place, old cached rta is possibly freed. */ enum filter_return -f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) +f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) { if (filter == FILTER_ACCEPT) return F_ACCEPT; @@ -886,12 +969,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla .rte = rte, .pool = tmp_pool, .flags = flags, - .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); - enum filter_return fret = interpret(&fs, filter->root); + enum filter_return fret = interpret(&fs, filter->root, NULL); if (fs.old_rta) { /* @@ -925,54 +1007,52 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla /* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */ enum filter_return -f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) +f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) { struct filter_state fs = { .rte = rte, .pool = tmp_pool, - .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); /* Note that in this function we assume that rte->attrs is private / uncached */ - return interpret(&fs, expr); + return interpret(&fs, expr, NULL); } enum filter_return -f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres) +f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) { struct filter_state fs = { .pool = tmp_pool, - .stack = filter_stack, }; LOG_BUFFER_INIT(fs.buf); - enum filter_return fret = interpret(&fs, expr); - *pres = filter_stack[0].val; + enum filter_return fret = interpret(&fs, expr, pres); return fret; } uint -f_eval_int(struct f_inst *expr) +f_eval_int(const struct f_line *expr) { /* Called independently in parse-time to eval expressions */ struct filter_state fs = { .pool = cfg_mem, - .stack = filter_stack, }; + struct f_val val; + LOG_BUFFER_INIT(fs.buf); - if (interpret(&fs, expr) > F_RETURN) + if (interpret(&fs, expr, &val) > F_RETURN) cf_error("Runtime error while evaluating expression"); - if (filter_stack[0].val.type != T_INT) + if (val.type != T_INT) cf_error("Integer expression expected"); - return filter_stack[0].val.val.i; + return val.val.i; } /** @@ -993,5 +1073,5 @@ filter_same(struct filter *new, struct filter *old) if (old == FILTER_ACCEPT || old == FILTER_REJECT || new == FILTER_ACCEPT || new == FILTER_REJECT) return 0; - return i_same(new->root, old->root); + return f_same(new->root, old->root); } diff --git a/filter/filter.h b/filter/filter.h index 594c9511..87bd2c36 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -14,13 +14,65 @@ #include "nest/route.h" #include "nest/attrs.h" +/* IP prefix range structure */ struct f_prefix { - net_addr net; - u8 lo, hi; + net_addr net; /* The matching prefix must match this net */ + u8 lo, hi; /* And its length must fit between lo and hi */ }; +/* Type numbers must be in 0..0xff range */ +#define T_MASK 0xff + +/* Internal types */ +enum f_type { +/* Do not use type of zero, that way we'll see errors easier. */ + T_VOID = 1, + +/* User visible types, which fit in int */ + T_INT = 0x10, + T_BOOL = 0x11, + T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ + T_QUAD = 0x13, + +/* Put enumerational types in 0x30..0x3f range */ + T_ENUM_LO = 0x30, + T_ENUM_HI = 0x3f, + + T_ENUM_RTS = 0x30, + T_ENUM_BGP_ORIGIN = 0x31, + T_ENUM_SCOPE = 0x32, + T_ENUM_RTC = 0x33, + T_ENUM_RTD = 0x34, + T_ENUM_ROA = 0x35, + T_ENUM_NETTYPE = 0x36, + T_ENUM_RA_PREFERENCE = 0x37, + +/* new enums go here */ + T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */ + +#define T_ENUM T_ENUM_LO ... T_ENUM_HI + +/* Bigger ones */ + T_IP = 0x20, + T_NET = 0x21, + T_STRING = 0x22, + T_PATH_MASK = 0x23, /* mask for BGP path */ + T_PATH = 0x24, /* BGP path */ + T_CLIST = 0x25, /* Community list */ + T_EC = 0x26, /* Extended community value, u64 */ + T_ECLIST = 0x27, /* Extended community list */ + T_LC = 0x28, /* Large community value, lcomm */ + T_LCLIST = 0x29, /* Large community list */ + T_RD = 0x2a, /* Route distinguisher for VPN addresses */ + T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ + + T_SET = 0x80, + T_PREFIX_SET = 0x81, +} PACKED; + +/* Filter value; size of this affects filter memory consumption */ struct f_val { - int type; /* T_* */ + enum f_type type; /* T_* */ union { uint i; u64 ec; @@ -28,27 +80,42 @@ struct f_val { ip_addr ip; const net_addr *net; char *s; - struct f_tree *t; - struct f_trie *ti; - struct adata *ad; - struct f_path_mask *path_mask; + const struct f_tree *t; + const struct f_trie *ti; + const struct adata *ad; + const struct f_path_mask *path_mask; + struct f_path_mask_item pmi; } val; }; +/* Dynamic attribute definition (eattrs) */ struct f_dynamic_attr { - int type; - int f_type; - int ea_code; + u8 type; /* EA type (EAF_*) */ + u8 bit; /* For bitfield accessors */ + enum f_type f_type; /* Filter type */ + uint ea_code; /* EA code */ }; +enum f_sa_code { + SA_FROM = 1, + SA_GW, + SA_NET, + SA_PROTO, + SA_SOURCE, + SA_SCOPE, + SA_DEST, + SA_IFNAME, + SA_IFINDEX, +} PACKED; + +/* Static attribute definition (members of struct rta) */ struct f_static_attr { - int f_type; - int sa_code; - int readonly; + enum f_type f_type; /* Filter type */ + enum f_sa_code sa_code; /* Static attribute id */ + int readonly:1; /* Don't allow writing */ }; -/* Filter instruction types */ - +/* Filter instruction words */ #define FI__TWOCHAR(a,b) ((a<<8) | b) #define FI__LIST \ F(FI_NOP, 0, '0') \ @@ -96,16 +163,20 @@ struct f_static_attr { F(FI_AS_PATH_LAST_NAG, 'a', 'L') \ F(FI_RETURN, 0, 'r') \ F(FI_CALL, 'c', 'a') \ + F(FI_DROP_RESULT, 'd', 'r') \ 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_CLIST_ADD, 'C', 'a') \ + F(FI_CLIST_DEL, 'C', 'd') \ + F(FI_CLIST_FILTER, 'C', 'f') \ + F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \ + F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \ F(FI_FORMAT, 0, 'F') \ F(FI_ASSERT, 'a', 's') +/* The enum itself */ enum f_instruction_code { #define F(c,a,b) \ c, @@ -114,58 +185,40 @@ FI__LIST FI__MAX, } PACKED; +/* Convert the instruction back to the enum name */ 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; +enum f_instruction_flags { + FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ +}; + +union f_inst_attr { + uint i; + void *p; + struct rtable_config *rtc; +}; + +/* Instruction structure for config */ +struct f_inst { + struct f_inst *next; /* Next instruction to be executed */ + enum f_instruction_code fi_code; /* The instruction itself */ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ union { - union { - uint i; - void *p; - struct rtable_config *rtc; - } a[3]; /* The three arguments */ + union f_inst_attr a[3]; /* The three arguments */ struct f_val val; /* The value if FI_CONSTANT */ + struct { + union f_inst_attr sa_a[1]; + struct f_static_attr sa; /* Static attribute def for FI_RTA_* */ + }; + struct { + union f_inst_attr da_a[1]; + struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */ + }; }; int lineno; }; -#define arg1 a[0].p -#define arg2 a[1].p -#define arg3 a[2].p - -struct filter { - char *name; - struct f_inst *root; -}; - -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_dynamic_attr da, struct f_inst *argument); -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 *); -struct f_tree *find_tree(struct f_tree *t, struct f_val val); -int same_tree(struct f_tree *t1, struct f_tree *t2); -void tree_format(struct f_tree *t, buffer *buf); - -struct f_trie *f_new_trie(linpool *lp, uint node_size); -void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); -int trie_match_net(struct f_trie *t, const net_addr *n); -int trie_same(struct f_trie *t1, struct f_trie *t2); -void trie_format(struct f_trie *t, buffer *buf); - -struct ea_list; -struct rte; - +/* Possible return values of filter execution */ enum filter_return { F_NOP = 0, F_NONL, @@ -176,83 +229,121 @@ enum filter_return { F_QUITBIRD, }; -enum filter_return f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); -enum filter_return f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); -enum filter_return f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres); -uint f_eval_int(struct f_inst *expr); +/* Filter structures for execution */ +struct f_line; + +/* The single instruction item */ +struct f_line_item { + enum f_instruction_code fi_code; /* What to do */ + enum f_instruction_flags flags; /* Flags, instruction-specific */ + uint lineno; /* Where */ + union { + struct { + const struct f_val *vp; + const struct symbol *sym; + }; + const struct f_line *lines[2]; + enum filter_return fret; + struct f_static_attr sa; + struct f_dynamic_attr da; + enum ec_subtype ecs; + const char *s; + const struct f_tree *tree; + const struct rtable_config *rtc; + uint count; + }; /* Additional instruction data */ +}; + +/* Line of instructions to be unconditionally executed one after another */ +struct f_line { + uint len; /* Line length */ + struct f_line_item items[0]; /* The items themselves */ +}; + +/* The filter encapsulating structure to be pointed-to from outside */ +struct filter { + char *name; + struct f_line *root; +}; + +/* Convert the f_inst infix tree to the f_line structures */ +struct f_line *f_postfixify_concat(struct f_inst *root, ...); +static inline struct f_line *f_postfixify(struct f_inst *root) +{ return f_postfixify_concat(root, NULL); } + +#define F_VAL_STACK_MAX 4096 + +/* Value stack for execution */ +struct f_val_stack { + uint cnt; /* Current stack size; 0 for empty */ + struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */ +}; + +#define F_EXEC_STACK_MAX 4096 + +/* Exception bits */ +enum f_exception { + FE_RETURN = 0x1, +}; + +/* Instruction stack for execution */ +struct f_exec_stack { + struct { + const struct f_line *line; /* The line that is being executed */ + uint pos; /* Instruction index in the line */ + uint ventry; /* Value stack depth on entry */ + enum f_exception emask; /* Exception mask */ + } item[F_EXEC_STACK_MAX]; + uint cnt; /* Current stack size; 0 for empty */ + +}; + +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(u8 type, 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 = type, .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 }; } +struct f_tree *f_new_tree(void); +struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); +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 *); +const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); +int same_tree(const struct f_tree *t1, const struct f_tree *t2); +void tree_format(const struct f_tree *t, buffer *buf); + +struct f_trie *f_new_trie(linpool *lp, uint node_size); +void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); +int trie_match_net(const struct f_trie *t, const net_addr *n); +int trie_same(const struct f_trie *t1, const struct f_trie *t2); +void trie_format(const struct f_trie *t, buffer *buf); + +struct ea_list; +struct rte; + +enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); +enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool); +enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); +uint f_eval_int(const struct f_line *expr); char *filter_name(struct filter *filter); int filter_same(struct filter *new, struct filter *old); -int i_same(struct f_inst *f1, struct f_inst *f2); +int f_same(const struct f_line *f1, const struct f_line *f2); -int val_compare(struct f_val v1, struct f_val v2); -int val_same(struct f_val v1, struct f_val v2); +int val_compare(const struct f_val *v1, const struct f_val *v2); -void val_format(struct f_val v, buffer *buf); +void val_format(const struct f_val *v, buffer *buf); + +extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) #define FILTER_UNDEF ((void *) 2) /* Used in BGP */ -/* Type numbers must be in 0..0xff range */ -#define T_MASK 0xff - -/* Internal types */ -/* Do not use type of zero, that way we'll see errors easier. */ -#define T_VOID 1 - -/* User visible types, which fit in int */ -#define T_INT 0x10 -#define T_BOOL 0x11 -#define T_PAIR 0x12 /* Notice that pair is stored as integer: first << 16 | second */ -#define T_QUAD 0x13 - -/* Put enumerational types in 0x30..0x3f range */ -#define T_ENUM_LO 0x30 -#define T_ENUM_HI 0x3f - -#define T_ENUM_RTS 0x30 -#define T_ENUM_BGP_ORIGIN 0x31 -#define T_ENUM_SCOPE 0x32 -#define T_ENUM_RTC 0x33 -#define T_ENUM_RTD 0x34 -#define T_ENUM_ROA 0x35 -#define T_ENUM_NETTYPE 0x36 -#define T_ENUM_RA_PREFERENCE 0x37 - -/* new enums go here */ -#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */ - -#define T_ENUM T_ENUM_LO ... T_ENUM_HI - -/* Bigger ones */ -#define T_IP 0x20 -#define T_NET 0x21 -#define T_STRING 0x22 -#define T_PATH_MASK 0x23 /* mask for BGP path */ -#define T_PATH 0x24 /* BGP path */ -#define T_CLIST 0x25 /* Community list */ -#define T_EC 0x26 /* Extended community value, u64 */ -#define T_ECLIST 0x27 /* Extended community list */ -#define T_LC 0x28 /* Large community value, lcomm */ -#define T_LCLIST 0x29 /* Large community list */ -#define T_RD 0x2a /* Route distinguisher for VPN addresses */ - -#define T_SET 0x80 -#define T_PREFIX_SET 0x81 - - -#define SA_FROM 1 -#define SA_GW 2 -#define SA_NET 3 -#define SA_PROTO 4 -#define SA_SOURCE 5 -#define SA_SCOPE 6 -#define SA_DEST 7 -#define SA_IFNAME 8 -#define SA_IFINDEX 9 - struct f_tree { struct f_tree *left, *right; @@ -291,12 +382,12 @@ struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type); /* Bird Tests */ struct f_bt_test_suite { node n; /* Node in config->tests */ - struct f_inst *fn; /* Root of function */ + struct f_line *fn; /* Root of function */ const char *fn_name; /* Name of test */ const char *dsc; /* Description */ }; /* Hook for call bt_assert() function in configuration */ -extern void (*bt_assert_hook)(int result, struct f_inst *assert); +extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); #endif diff --git a/filter/filter_test.c b/filter/filter_test.c index 32555d82..e19b0a75 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -40,8 +40,7 @@ parse_config_file(const void *filename_void) static int run_function(const void *parsed_fn_def) { - /* XXX: const -> non-const */ - struct f_inst *f = (struct f_inst *) parsed_fn_def; + const struct f_line *f = (const struct f_line *) parsed_fn_def; linpool *tmp = lp_new_default(&root_pool); struct f_val res; @@ -52,7 +51,7 @@ run_function(const void *parsed_fn_def) } static void -bt_assert_filter(int result, struct f_inst *assert) +bt_assert_filter(int result, const struct f_line_item *assert) { int bt_suit_case_result = 1; if (!result) @@ -62,7 +61,7 @@ bt_assert_filter(int result, struct f_inst *assert) bt_suit_case_result = 0; } - bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a[1].p); + bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, assert->s); } int diff --git a/filter/interpret.m4 b/filter/interpret.m4 index d1c83389..829b48f6 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -10,7 +10,60 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `break; case $1:') +m4_define(INST, `break; case $1: +m4_ifelse(eval($2 > 0), `if (vstk.cnt < $2) runtime("Stack underflow");', `') +vstk.cnt -= $2; +') +m4_define(ARG, `if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)') + +m4_define(RESULT_OK, `vstk.cnt++') +m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') +m4_define(RESULT_VAL, `do { res = $1; RESULT_OK; } while (0)') + +m4_define(LINEX, `do { + estk.item[estk.cnt].pos = 0; + estk.item[estk.cnt].line = $1; + estk.item[estk.cnt].ventry = vstk.cnt; + estk.item[estk.cnt].emask = 0; + estk.cnt++; +} while (0)') + +m4_define(LINE, `do { + if (what->lines[$2]) { + estk.item[estk.cnt].pos = 0; + estk.item[estk.cnt].line = what->lines[$2]; + estk.item[estk.cnt].ventry = vstk.cnt; + estk.item[estk.cnt].emask = 0; + estk.cnt++; + } +} while (0)') + +m4_define(LINEP, LINE($1, $2)) + +m4_define(ARG_ANY, `') + +m4_define(SYMBOL, `const struct symbol *sym = what->sym') + +m4_define(VALI, `res = *what->vp') +m4_define(VALP, `res = *what->vp') +m4_define(FRET, `enum filter_return fret = what->fret') +m4_define(ECS, `enum ec_subtype ecs = what->ecs') +m4_define(RTC, `struct rtable *table = what->rtc->table') +m4_define(STATIC_ATTR, `struct f_static_attr sa = what->sa') +m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da') +m4_define(POSTFIXIFY, `') +m4_define(LINE_SIZE, `') +m4_define(SAME, `') +m4_define(COUNT, `') + +m4_m4wrap(` +m4_divert(0)DNL +case FI_NOP: bug("This shall not happen"); +m4_undivert(1) +break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +') + +m4_divert(1) m4_changequote([[,]]) -m4_divert(0) + diff --git a/filter/line-size.m4 b/filter/line-size.m4 new file mode 100644 index 00000000..0c005fa1 --- /dev/null +++ b/filter/line-size.m4 @@ -0,0 +1,30 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Line size counting +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(INST, `m4_divert(1)break; case $1: cnt += 1; +m4_divert(-1)') +m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_divert(-1)') +m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_divert(-1)') +m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_divert(-1)') +m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)') + +m4_m4wrap(` +m4_divert(0)DNL +case FI_NOP: bug("This shall not happen"); +m4_undivert(1) +break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +') + +m4_changequote([[,]]) diff --git a/filter/postfixify.m4 b/filter/postfixify.m4 new file mode 100644 index 00000000..8c96ba64 --- /dev/null +++ b/filter/postfixify.m4 @@ -0,0 +1,55 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Converting instructions trees to instruction lines +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what->fi_code; +dest->items[pos].lineno = what->lineno;') + +m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER +break; case $1: +m4_divert(-1)')) +m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos); +m4_divert(-1)') +m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos); +m4_divert(-1)') +m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p); +m4_divert(-1)') +m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p; +m4_divert(-1)') +m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p; +m4_divert(-1)') +m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val); +m4_divert(-1)') +m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def; +m4_divert(-1)') +m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i; +m4_divert(-1)') +m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux; +m4_divert(-1)') +m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc; +m4_divert(-1)') +m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa; +m4_divert(-1)') +m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da; +m4_divert(-1)') +m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->a[$1-1].i; +m4_divert(-1)') +m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)') + +m4_m4wrap(` +m4_divert(0)DNL +case FI_NOP: bug("This shall not happen"); +m4_undivert(1) +POSTFIXIFY_TRAILER +break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +') + +m4_changequote([[,]]) diff --git a/filter/same.m4 b/filter/same.m4 new file mode 100644 index 00000000..73f2d1c3 --- /dev/null +++ b/filter/same.m4 @@ -0,0 +1,56 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Filter Comparator Generator +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(INST, `m4_divert(1)break; case $1: +m4_divert(-1)') + +m4_define(ARG, `') +m4_define(ARG_ANY, `') + +m4_define(LINE, `m4_divert(1)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; +m4_divert(-1)') +m4_define(LINEP, LINE) + +m4_define(SYMBOL, `m4_divert(1){ + const struct symbol *s1 = f1->sym, *s2 = f2->sym; + if (strcmp(s1->name, s2->name)) return 0; + if (s1->class != s2->class) return 0; +} +m4_divert(-1)') + +m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0; +m4_divert(-1)') +m4_define(VALP, `') + +m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0; +m4_divert(-1)') +m4_define(ECS, `m4_divert(1)if (f1->ecs != f2->ecs) return 0; +m4_divert(-1)') +m4_define(RTC, `m4_divert(1)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0; +m4_divert(-1)') +m4_define(STATIC_ATTR, `m4_divert(1)if (f1->sa.sa_code != f2->sa.sa_code) return 0; +m4_divert(-1)') +m4_define(DYNAMIC_ATTR, `m4_divert(1)if (f1->da.ea_code != f2->da.ea_code) return 0; +m4_divert(-1)') + +m4_define(SAME, `m4_divert(1)$1m4_divert(-1)') + +m4_m4wrap(` +m4_divert(0)DNL +case FI_NOP: bug("This shall not happen"); +m4_undivert(1) +break; default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff); +') + +m4_divert(1) +m4_changequote([[,]]) + diff --git a/filter/tree.c b/filter/tree.c index f8379fa8..80e1d395 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -23,15 +23,15 @@ * Both set matching and |switch() { }| construction is implemented using this function, * thus both are as fast as they can be. */ -struct f_tree * -find_tree(struct f_tree *t, struct f_val val) +const struct f_tree * +find_tree(const struct f_tree *t, const struct f_val *val) { if (!t) return NULL; - if ((val_compare(t->from, val) != 1) && - (val_compare(t->to, val) != -1)) + if ((val_compare(&(t->from), val) != 1) && + (val_compare(&(t->to), val) != -1)) return t; - if (val_compare(t->from, val) == -1) + if (val_compare(&(t->from), val) == -1) return find_tree(t->right, val); else return find_tree(t->left, val); @@ -56,7 +56,7 @@ build_tree_rec(struct f_tree **buf, int l, int h) static int tree_compare(const void *p1, const void *p2) { - return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); + return val_compare(&((* (struct f_tree **) p1)->from), &((* (struct f_tree **) p2)->from)); } /** @@ -119,39 +119,39 @@ f_new_tree(void) * Compares two trees and returns 1 if they are same */ int -same_tree(struct f_tree *t1, struct f_tree *t2) +same_tree(const struct f_tree *t1, const struct f_tree *t2) { if ((!!t1) != (!!t2)) return 0; if (!t1) return 1; - if (val_compare(t1->from, t2->from)) + if (val_compare(&(t1->from), &(t2->from))) return 0; - if (val_compare(t1->to, t2->to)) + if (val_compare(&(t1->to), &(t2->to))) return 0; if (!same_tree(t1->left, t2->left)) return 0; if (!same_tree(t1->right, t2->right)) return 0; - if (!i_same(t1->data, t2->data)) + if (!f_same(t1->data, t2->data)) return 0; return 1; } static void -tree_node_format(struct f_tree *t, buffer *buf) +tree_node_format(const struct f_tree *t, buffer *buf) { if (t == NULL) return; tree_node_format(t->left, buf); - val_format(t->from, buf); - if (val_compare(t->from, t->to) != 0) + val_format(&(t->from), buf); + if (val_compare(&(t->from), &(t->to)) != 0) { buffer_puts(buf, ".."); - val_format(t->to, buf); + val_format(&(t->to), buf); } buffer_puts(buf, ", "); @@ -159,7 +159,7 @@ tree_node_format(struct f_tree *t, buffer *buf) } void -tree_format(struct f_tree *t, buffer *buf) +tree_format(const struct f_tree *t, buffer *buf) { buffer_puts(buf, "["); diff --git a/filter/tree_test.c b/filter/tree_test.c index 5b22a9fe..f3e8ce49 100644 --- a/filter/tree_test.c +++ b/filter/tree_test.c @@ -226,8 +226,8 @@ t_find(void) }; for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++) { - struct f_tree *found_tree = find_tree(tree, looking_up_value); - bt_assert((val_compare(looking_up_value, found_tree->from) == 0) && (val_compare(looking_up_value, found_tree->to) == 0)); + const struct f_tree *found_tree = find_tree(tree, &looking_up_value); + bt_assert((val_compare(&looking_up_value, &(found_tree->from)) == 0) && (val_compare(&looking_up_value, &(found_tree->to)) == 0)); } } @@ -278,11 +278,11 @@ t_find_ranges(void) for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count) { - struct f_tree *found_tree = find_tree(tree, needle); + const struct f_tree *found_tree = find_tree(tree, &needle); bt_debug("searching: %u \n", *i); bt_assert( - (val_compare(needle, found_tree->from) == 0) || (val_compare(needle, found_tree->to) == 0) || - ((val_compare(needle, found_tree->from) == 1) && (val_compare(needle, found_tree->to) == -1)) + (val_compare(&needle, &(found_tree->from)) == 0) || (val_compare(&needle, &(found_tree->to)) == 0) || + ((val_compare(&needle, &(found_tree->from)) == 1) && (val_compare(&needle, &(found_tree->to)) == -1)) ); } } diff --git a/filter/trie.c b/filter/trie.c index adcfcdf3..a279e38c 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -220,7 +220,7 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h) } static int -trie_match_prefix(struct f_trie *t, ip_addr px, uint plen) +trie_match_prefix(const struct f_trie *t, ip_addr px, uint plen) { ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); @@ -229,7 +229,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen) return t->zero; int plentest = plen - 1; - struct f_trie_node *n = t->root; + const struct f_trie_node *n = t->root; while(n) { @@ -264,7 +264,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen) * is such prefix pattern in the trie. */ int -trie_match_net(struct f_trie *t, const net_addr *n) +trie_match_net(const struct f_trie *t, const net_addr *n) { uint add = 0; @@ -279,7 +279,7 @@ trie_match_net(struct f_trie *t, const net_addr *n) } static int -trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2) +trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2) { if ((t1 == NULL) && (t2 == NULL)) return 1; @@ -303,13 +303,13 @@ trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2) * Compares two tries and returns 1 if they are same */ int -trie_same(struct f_trie *t1, struct f_trie *t2) +trie_same(const struct f_trie *t1, const struct f_trie *t2) { return (t1->zero == t2->zero) && trie_node_same(t1->root, t2->root); } static void -trie_node_format(struct f_trie_node *t, buffer *buf) +trie_node_format(const struct f_trie_node *t, buffer *buf) { if (t == NULL) return; @@ -329,7 +329,7 @@ trie_node_format(struct f_trie_node *t, buffer *buf) * Prints the trie to the supplied buffer. */ void -trie_format(struct f_trie *t, buffer *buf) +trie_format(const struct f_trie *t, buffer *buf) { buffer_puts(buf, "["); diff --git a/lib/ip.h b/lib/ip.h index b78a5e22..945f2893 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -354,12 +354,12 @@ mpls_put(char *buf, int len, u32 *stack) * Unaligned data access (in network order) */ -static inline ip4_addr get_ip4(void *buf) +static inline ip4_addr get_ip4(const void *buf) { return _MI4(get_u32(buf)); } -static inline ip6_addr get_ip6(void *buf) +static inline ip6_addr get_ip6(const void *buf) { ip6_addr a; memcpy(&a, buf, 16); diff --git a/nest/a-path.c b/nest/a-path.c index 6f1c40bf..d3a1d636 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -77,10 +77,10 @@ bad: } int -as_path_16to32(byte *dst, byte *src, uint len) +as_path_16to32(byte *dst, const byte *src, uint len) { byte *dst0 = dst; - byte *end = src + len; + const byte *end = src + len; uint i, n; while (src < end) @@ -101,10 +101,10 @@ as_path_16to32(byte *dst, byte *src, uint len) } int -as_path_32to16(byte *dst, byte *src, uint len) +as_path_32to16(byte *dst, const byte *src, uint len) { byte *dst0 = dst; - byte *end = src + len; + const byte *end = src + len; uint i, n; while (src < end) @@ -273,11 +273,11 @@ as_path_to_old(struct linpool *pool, const struct adata *path) * AS_CONFED_* segments have zero length and must be added if they are on edge. * In contrast to other as_path_* functions, @path is modified in place. */ -void -as_path_cut(struct adata *path, uint num) +struct adata * +as_path_cut(struct linpool *pool, const struct adata *path, uint num) { - byte *pos = path->data; - byte *end = pos + path->length; + const byte *pos = path->data; + const byte *end = pos + path->length; while (pos < end) { @@ -297,28 +297,39 @@ as_path_cut(struct adata *path, uint num) /* Cannot add whole segment, so try partial one and finish */ if (num < n) { + const byte *nend = pos; + if (num) + nend += 2 + BS * num; + + struct adata *res = lp_alloc_adata(pool, path->length); + res->length = nend - (const byte *) path->data; + memcpy(res->data, path->data, res->length); + if (num) { - pos[1] = num; - pos += 2 + BS * num; + byte *dpos = ((byte *) res->data) + (pos - (const byte *) path->data); + dpos[1] = num; } - break; + return res; } num -= n; pos += 2 + BS * l; } - path->length = pos - path->data; + struct adata *res = lp_alloc_adata(pool, path->length); + res->length = path->length; + memcpy(res->data, path->data, res->length); + return res; } /* * Merge (concatenate) paths @p1 and @p2 and return the result. * In contrast to other as_path_* functions, @p1 and @p2 may be reused. */ -struct adata * -as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2) +const struct adata * +as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2) { if (p1->length == 0) return p2; @@ -561,7 +572,7 @@ as_path_contains(const struct adata *path, u32 as, int min) } int -as_path_match_set(const struct adata *path, struct f_tree *set) +as_path_match_set(const struct adata *path, const struct f_tree *set) { const u8 *p = path->data; const u8 *q = p+path->length; @@ -574,7 +585,7 @@ as_path_match_set(const struct adata *path, struct f_tree *set) for (i=0; ilen; m++) { /* We remove this mark to not step after pos[plen] */ pos[plen].mark = 0; - switch (mask->kind) + switch (mask->item[m].kind) { case PM_ASTERISK: for (i = l; i <= plen; i++) @@ -802,13 +816,13 @@ as_path_match(const struct adata *path, struct f_path_mask *mask) break; case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */ - val2 = val = mask->val; + val2 = val = mask->item[m].asn; goto step; case PM_ASN_EXPR: bug("Expressions should be evaluated on AS path mask construction."); case PM_ASN_RANGE: - val = mask->val; - val2 = mask->val2; + val = mask->item[m].from; + val2 = mask->item[m].to; goto step; case PM_QUESTION: step: @@ -817,7 +831,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask) if (pos[i].mark) { pos[i].mark = 0; - if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2)) + if ((mask->item[m].kind == PM_QUESTION) || pm_match(pos + i, val, val2)) pm_mark(pos, i, plen, &nl, &nh); } @@ -828,8 +842,6 @@ as_path_match(const struct adata *path, struct f_path_mask *mask) l = nl; break; } - - mask = mask->next; } return pos[plen].mark; diff --git a/nest/a-path_test.c b/nest/a-path_test.c index a71b48ba..9ed0a786 100644 --- a/nest/a-path_test.c +++ b/nest/a-path_test.c @@ -34,26 +34,24 @@ t_as_path_match(void) first_prepended = last_prepended = 0; struct linpool *lp = lp_new_default(&root_pool); - struct f_path_mask mask[AS_PATH_LENGTH] = {}; - int i; - for (i = 0; i < AS_PATH_LENGTH; i++) + struct f_path_mask *mask = alloca(sizeof(struct f_path_mask) + AS_PATH_LENGTH * sizeof(struct f_path_mask_item)); + mask->len = AS_PATH_LENGTH; + for (int i = AS_PATH_LENGTH - 1; i >= 0; i--) { u32 val = bt_random(); as_path = as_path_prepend(lp, as_path, val); bt_debug("Prepending ASN: %10u \n", val); if (i == 0) - first_prepended = val; - if (i == AS_PATH_LENGTH-1) last_prepended = val; + if (i == AS_PATH_LENGTH-1) + first_prepended = val; - mask[i].kind = PM_ASN; - mask[i].val = val; - if (i) - mask[i].next = &mask[i-1]; + mask->item[i].kind = PM_ASN; + mask->item[i].asn = val; } - bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path"); + bt_assert_msg(as_path_match(as_path, mask), "Mask should match with AS path"); u32 asn; diff --git a/nest/a-set.c b/nest/a-set.c index 048e522d..10ddd139 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -34,7 +34,7 @@ * the buffer to indicate truncation. */ int -int_set_format(struct adata *set, int way, int from, byte *buf, uint size) +int_set_format(const struct adata *set, int way, int from, byte *buf, uint size) { u32 *z = (u32 *) set->data; byte *end = buf + size - 24; @@ -115,7 +115,7 @@ ec_format(byte *buf, u64 ec) } int -ec_set_format(struct adata *set, int from, byte *buf, uint size) +ec_set_format(const struct adata *set, int from, byte *buf, uint size) { u32 *z = int_set_get_data(set); byte *end = buf + size - 64; @@ -150,7 +150,7 @@ lc_format(byte *buf, lcomm lc) } int -lc_set_format(struct adata *set, int from, byte *buf, uint bufsize) +lc_set_format(const struct adata *set, int from, byte *buf, uint bufsize) { u32 *d = (u32 *) set->data; byte *end = buf + bufsize - 64; @@ -181,7 +181,7 @@ lc_set_format(struct adata *set, int from, byte *buf, uint bufsize) } int -int_set_contains(struct adata *list, u32 val) +int_set_contains(const struct adata *list, u32 val) { if (!list) return 0; @@ -198,7 +198,7 @@ int_set_contains(struct adata *list, u32 val) } int -ec_set_contains(struct adata *list, u64 val) +ec_set_contains(const struct adata *list, u64 val) { if (!list) return 0; @@ -217,7 +217,7 @@ ec_set_contains(struct adata *list, u64 val) } int -lc_set_contains(struct adata *list, lcomm val) +lc_set_contains(const struct adata *list, lcomm val) { if (!list) return 0; @@ -233,8 +233,8 @@ lc_set_contains(struct adata *list, lcomm val) return 0; } -struct adata * -int_set_prepend(struct linpool *pool, struct adata *list, u32 val) +const struct adata * +int_set_prepend(struct linpool *pool, const struct adata *list, u32 val) { struct adata *res; int len; @@ -254,8 +254,8 @@ int_set_prepend(struct linpool *pool, struct adata *list, u32 val) return res; } -struct adata * -int_set_add(struct linpool *pool, struct adata *list, u32 val) +const struct adata * +int_set_add(struct linpool *pool, const struct adata *list, u32 val) { struct adata *res; int len; @@ -275,8 +275,8 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val) return res; } -struct adata * -ec_set_add(struct linpool *pool, struct adata *list, u64 val) +const struct adata * +ec_set_add(struct linpool *pool, const struct adata *list, u64 val) { if (ec_set_contains(list, val)) return list; @@ -295,8 +295,8 @@ ec_set_add(struct linpool *pool, struct adata *list, u64 val) return res; } -struct adata * -lc_set_add(struct linpool *pool, struct adata *list, lcomm val) +const struct adata * +lc_set_add(struct linpool *pool, const struct adata *list, lcomm val) { if (lc_set_contains(list, val)) return list; @@ -313,8 +313,8 @@ lc_set_add(struct linpool *pool, struct adata *list, lcomm val) return res; } -struct adata * -int_set_del(struct linpool *pool, struct adata *list, u32 val) +const struct adata * +int_set_del(struct linpool *pool, const struct adata *list, u32 val) { if (!int_set_contains(list, val)) return list; @@ -335,8 +335,8 @@ int_set_del(struct linpool *pool, struct adata *list, u32 val) return res; } -struct adata * -ec_set_del(struct linpool *pool, struct adata *list, u64 val) +const struct adata * +ec_set_del(struct linpool *pool, const struct adata *list, u64 val) { if (!ec_set_contains(list, val)) return list; @@ -362,8 +362,8 @@ ec_set_del(struct linpool *pool, struct adata *list, u64 val) return res; } -struct adata * -lc_set_del(struct linpool *pool, struct adata *list, lcomm val) +const struct adata * +lc_set_del(struct linpool *pool, const struct adata *list, lcomm val) { if (!lc_set_contains(list, val)) return list; @@ -384,8 +384,8 @@ lc_set_del(struct linpool *pool, struct adata *list, lcomm val) return res; } -struct adata * -int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) +const struct adata * +int_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2) { if (!l1) return l2; @@ -414,8 +414,8 @@ int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) return res; } -struct adata * -ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) +const struct adata * +ec_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2) { if (!l1) return l2; @@ -447,8 +447,8 @@ ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) return res; } -struct adata * -lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) +const struct adata * +lc_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2) { if (!l1) return l2; @@ -479,7 +479,7 @@ lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) struct adata * -ec_set_del_nontrans(struct linpool *pool, struct adata *set) +ec_set_del_nontrans(struct linpool *pool, const struct adata *set) { adata *res = lp_alloc_adata(pool, set->length); u32 *src = int_set_get_data(set); @@ -510,7 +510,7 @@ int_set_cmp(const void *X, const void *Y) } struct adata * -int_set_sort(struct linpool *pool, struct adata *src) +int_set_sort(struct linpool *pool, const struct adata *src) { struct adata *dst = lp_alloc_adata(pool, src->length); memcpy(dst->data, src->data, src->length); @@ -528,7 +528,7 @@ ec_set_cmp(const void *X, const void *Y) } struct adata * -ec_set_sort(struct linpool *pool, struct adata *src) +ec_set_sort(struct linpool *pool, const struct adata *src) { struct adata *dst = lp_alloc_adata(pool, src->length); memcpy(dst->data, src->data, src->length); @@ -558,7 +558,7 @@ lc_set_cmp(const void *X, const void *Y) } struct adata * -lc_set_sort(struct linpool *pool, struct adata *src) +lc_set_sort(struct linpool *pool, const struct adata *src) { struct adata *dst = lp_alloc_adata(pool, src->length); memcpy(dst->data, src->data, src->length); diff --git a/nest/a-set_test.c b/nest/a-set_test.c index a5081f9f..96b6a727 100644 --- a/nest/a-set_test.c +++ b/nest/a-set_test.c @@ -15,10 +15,10 @@ #include "lib/resource.h" #define SET_SIZE 10 -static struct adata *set_sequence; /* <0; SET_SIZE) */ -static struct adata *set_sequence_same; /* <0; SET_SIZE) */ -static struct adata *set_sequence_higher; /* length = 4 * SET_SIZE_FOR_FORMAT_OUTPUT; /* dirty */ bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0); bt_assert(strcmp(buf, "0.0.0.0 0.0.0.1 0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0); @@ -134,9 +133,9 @@ static int t_set_int_delete(void) { resource_init(); - generate_set_sequence(SET_TYPE_INT); + generate_set_sequence(SET_TYPE_INT, SET_SIZE); - struct adata *deleting_sequence = set_sequence; + const struct adata *deleting_sequence = set_sequence; u32 i; for (i = 0; i < SET_SIZE; i++) { @@ -162,7 +161,7 @@ t_set_ec_contains(void) u32 i; resource_init(); - generate_set_sequence(SET_TYPE_EC); + generate_set_sequence(SET_TYPE_EC, SET_SIZE); bt_assert(ec_set_get_size(set_sequence) == SET_SIZE); @@ -183,9 +182,9 @@ static int t_set_ec_union(void) { resource_init(); - generate_set_sequence(SET_TYPE_EC); + generate_set_sequence(SET_TYPE_EC, SET_SIZE); - struct adata *set_union; + const struct adata *set_union; set_union = ec_set_union(lp, set_sequence, set_sequence_same); bt_assert(ec_set_get_size(set_union) == SET_SIZE); bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0); @@ -203,7 +202,7 @@ t_set_ec_format(void) { resource_init(); - struct adata empty_as_path = {}; + const struct adata empty_as_path = {}; set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path; lp = lp_new_default(&root_pool); @@ -224,9 +223,9 @@ static int t_set_ec_delete(void) { resource_init(); - generate_set_sequence(SET_TYPE_EC); + generate_set_sequence(SET_TYPE_EC, SET_SIZE); - struct adata *deleting_sequence = set_sequence; + const struct adata *deleting_sequence = set_sequence; u32 i; for (i = 0; i < SET_SIZE; i++) { diff --git a/nest/attrs.h b/nest/attrs.h index 102f378a..d9d97136 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -31,15 +31,15 @@ struct f_tree; int as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen); -int as_path_16to32(byte *dst, byte *src, uint len); -int as_path_32to16(byte *dst, byte *src, uint len); +int as_path_16to32(byte *dst, const byte *src, uint len); +int as_path_32to16(byte *dst, const byte *src, uint len); int as_path_contains_as4(const struct adata *path); int as_path_contains_confed(const struct adata *path); struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op); struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as); struct adata *as_path_to_old(struct linpool *pool, const struct adata *path); -void as_path_cut(struct adata *path, uint num); -struct adata *as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2); +struct adata *as_path_cut(struct linpool *pool, const struct adata *path, uint num); +const struct adata *as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2); void as_path_format(const struct adata *path, byte *buf, uint size); int as_path_getlen(const struct adata *path); int as_path_getlen_int(const struct adata *path, int bs); @@ -48,8 +48,8 @@ int as_path_get_first_regular(const struct adata *path, u32 *last_as); int as_path_get_last(const struct adata *path, u32 *last_as); u32 as_path_get_last_nonaggregated(const struct adata *path); int as_path_contains(const struct adata *path, u32 as, int min); -int as_path_match_set(const struct adata *path, struct f_tree *set); -struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos); +int as_path_match_set(const struct adata *path, const struct f_tree *set); +const struct adata *as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tree *set, u32 key, int pos); static inline struct adata *as_path_prepend(struct linpool *pool, const struct adata *path, u32 as) { return as_path_prepend2(pool, path, AS_PATH_SEQUENCE, as); } @@ -61,20 +61,30 @@ static inline struct adata *as_path_prepend(struct linpool *pool, const struct a #define PM_ASN_EXPR 3 #define PM_ASN_RANGE 4 -struct f_path_mask { - struct f_path_mask *next; +struct f_path_mask_item { + union { + u32 asn; /* PM_ASN */ + struct f_line *expr; /* PM_ASN_EXPR */ + struct { /* PM_ASN_RANGE */ + u32 from; + u32 to; + }; + }; int kind; - uintptr_t val; - uintptr_t val2; }; -int as_path_match(const struct adata *path, struct f_path_mask *mask); +struct f_path_mask { + uint len; + struct f_path_mask_item item[0]; +}; + +int as_path_match(const struct adata *path, const struct f_path_mask *mask); /* Counterparts to appropriate as_path_* functions */ static inline int -aggregator_16to32(byte *dst, byte *src) +aggregator_16to32(byte *dst, const byte *src) { put_u32(dst, get_u16(src)); memcpy(dst+4, src+2, 4); @@ -82,7 +92,7 @@ aggregator_16to32(byte *dst, byte *src) } static inline int -aggregator_32to16(byte *dst, byte *src) +aggregator_32to16(byte *dst, const byte *src) { put_u16(dst, get_u32(src)); memcpy(dst+2, src+4, 4); @@ -90,13 +100,13 @@ aggregator_32to16(byte *dst, byte *src) } static inline int -aggregator_contains_as4(struct adata *a) +aggregator_contains_as4(const struct adata *a) { return get_u32(a->data) > 0xFFFF; } static inline struct adata * -aggregator_to_old(struct linpool *pool, struct adata *a) +aggregator_to_old(struct linpool *pool, const struct adata *a) { struct adata *d = lp_alloc_adata(pool, 8); put_u32(d->data, 0xFFFF); @@ -109,26 +119,27 @@ aggregator_to_old(struct linpool *pool, struct adata *a) /* Extended Community subtypes (kinds) */ -#define EC_RT 0x0002 -#define EC_RO 0x0003 - -#define EC_GENERIC 0xFFFF +enum ec_subtype { + EC_RT = 0x0002, + EC_RO = 0x0003, + EC_GENERIC = 0xFFFF, +} PACKED; /* Transitive bit (for first u32 half of EC) */ #define EC_TBIT 0x40000000 #define ECOMM_LENGTH 8 -static inline int int_set_get_size(struct adata *list) +static inline int int_set_get_size(const struct adata *list) { return list->length / 4; } -static inline int ec_set_get_size(struct adata *list) +static inline int ec_set_get_size(const struct adata *list) { return list->length / 8; } -static inline int lc_set_get_size(struct adata *list) +static inline int lc_set_get_size(const struct adata *list) { return list->length / 12; } -static inline u32 *int_set_get_data(struct adata *list) +static inline u32 *int_set_get_data(const struct adata *list) { return (u32 *) list->data; } static inline u32 ec_hi(u64 ec) { return ec >> 32; } @@ -137,16 +148,16 @@ static inline u64 ec_get(const u32 *l, int i) { return (((u64) l[i]) << 32) | l[i+1]; } /* RFC 4360 3.1. Two-Octet AS Specific Extended Community */ -static inline u64 ec_as2(u64 kind, u64 key, u64 val) -{ return ((kind | 0x0000) << 48) | (key << 32) | val; } +static inline u64 ec_as2(enum ec_subtype kind, u64 key, u64 val) +{ return (((u64) kind | 0x0000) << 48) | (key << 32) | val; } /* RFC 5668 4-Octet AS Specific BGP Extended Community */ -static inline u64 ec_as4(u64 kind, u64 key, u64 val) -{ return ((kind | 0x0200) << 48) | (key << 16) | val; } +static inline u64 ec_as4(enum ec_subtype kind, u64 key, u64 val) +{ return (((u64) kind | 0x0200) << 48) | (key << 16) | val; } /* RFC 4360 3.2. IPv4 Address Specific Extended Community */ -static inline u64 ec_ip4(u64 kind, u64 key, u64 val) -{ return ((kind | 0x0100) << 48) | (key << 16) | val; } +static inline u64 ec_ip4(enum ec_subtype kind, u64 key, u64 val) +{ return (((u64) kind | 0x0100) << 48) | (key << 16) | val; } static inline u64 ec_generic(u64 key, u64 val) { return (key << 32) | val; } @@ -173,29 +184,29 @@ static inline u32 *lc_copy(u32 *dst, const u32 *src) { memcpy(dst, src, LCOMM_LENGTH); return dst + 3; } -int int_set_format(struct adata *set, int way, int from, byte *buf, uint size); +int int_set_format(const struct adata *set, int way, int from, byte *buf, uint size); int ec_format(byte *buf, u64 ec); -int ec_set_format(struct adata *set, int from, byte *buf, uint size); +int ec_set_format(const struct adata *set, int from, byte *buf, uint size); int lc_format(byte *buf, lcomm lc); -int lc_set_format(struct adata *set, int from, byte *buf, uint size); -int int_set_contains(struct adata *list, u32 val); -int ec_set_contains(struct adata *list, u64 val); -int lc_set_contains(struct adata *list, lcomm val); -struct adata *int_set_prepend(struct linpool *pool, struct adata *list, u32 val); -struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); -struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val); -struct adata *lc_set_add(struct linpool *pool, struct adata *list, lcomm val); -struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val); -struct adata *ec_set_del(struct linpool *pool, struct adata *list, u64 val); -struct adata *lc_set_del(struct linpool *pool, struct adata *list, lcomm val); -struct adata *int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2); -struct adata *ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2); -struct adata *lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2); +int lc_set_format(const struct adata *set, int from, byte *buf, uint size); +int int_set_contains(const struct adata *list, u32 val); +int ec_set_contains(const struct adata *list, u64 val); +int lc_set_contains(const struct adata *list, lcomm val); +const struct adata *int_set_prepend(struct linpool *pool, const struct adata *list, u32 val); +const struct adata *int_set_add(struct linpool *pool, const struct adata *list, u32 val); +const struct adata *ec_set_add(struct linpool *pool, const struct adata *list, u64 val); +const struct adata *lc_set_add(struct linpool *pool, const struct adata *list, lcomm val); +const struct adata *int_set_del(struct linpool *pool, const struct adata *list, u32 val); +const struct adata *ec_set_del(struct linpool *pool, const struct adata *list, u64 val); +const struct adata *lc_set_del(struct linpool *pool, const struct adata *list, lcomm val); +const struct adata *int_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2); +const struct adata *ec_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2); +const struct adata *lc_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2); -struct adata *ec_set_del_nontrans(struct linpool *pool, struct adata *set); -struct adata *int_set_sort(struct linpool *pool, struct adata *src); -struct adata *ec_set_sort(struct linpool *pool, struct adata *src); -struct adata *lc_set_sort(struct linpool *pool, struct adata *src); +struct adata *ec_set_del_nontrans(struct linpool *pool, const struct adata *set); +struct adata *int_set_sort(struct linpool *pool, const struct adata *src); +struct adata *ec_set_sort(struct linpool *pool, const struct adata *src); +struct adata *lc_set_sort(struct linpool *pool, const struct adata *src); void ec_set_sort_x(struct adata *set); /* Sort in place */ diff --git a/nest/cmds.c b/nest/cmds.c index 0c89d20f..6daafcb3 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -95,8 +95,9 @@ cmd_show_memory(void) } void -cmd_eval(struct f_inst *expr) +cmd_eval(const struct f_line *expr) { + /* TODO: Return directly the string from eval */ struct f_val v; if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN) { @@ -106,6 +107,6 @@ cmd_eval(struct f_inst *expr) buffer buf; LOG_BUFFER_INIT(buf); - val_format(v, &buf); + val_format(&v, &buf); cli_msg(23, "%s", buf.start); } diff --git a/nest/cmds.h b/nest/cmds.h index 4cf8fb1b..194a9d7f 100644 --- a/nest/cmds.h +++ b/nest/cmds.h @@ -16,4 +16,6 @@ struct f_inst; void cmd_show_status(void); void cmd_show_symbols(struct sym_show_data *sym); void cmd_show_memory(void); -void cmd_eval(struct f_inst *expr); + +struct f_line; +void cmd_eval(const struct f_line *expr); diff --git a/nest/config.Y b/nest/config.Y index aef5ed46..51fb0bd7 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -112,7 +112,7 @@ rtrid: idval: NUM { $$ = $1; } - | '(' term ')' { $$ = f_eval_int($2); } + | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } | IP4 { $$ = ip4_to_u32($1); } | SYM { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) @@ -732,7 +732,7 @@ CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { protos_dump_all(); cli_msg(0, ""); } ; CF_CLI(EVAL, term, , [[Evaluate an expression]]) -{ cmd_eval($2); } ; +{ cmd_eval(f_postfixify($2)); } ; CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]]) CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [], [[Control echoing of log messages]]) { @@ -790,7 +790,7 @@ proto_patt2: | TEXT { $$.ptr = $1; $$.patt = 1; } ; -dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ; +dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_GEN_IGP_METRIC); } ; CF_CODE diff --git a/nest/route.h b/nest/route.h index 74446f48..c7ed80ff 100644 --- a/nest/route.h +++ b/nest/route.h @@ -473,7 +473,7 @@ typedef struct eattr { byte type; /* Attribute type and several flags (EAF_...) */ union { u32 data; - struct adata *ptr; /* Attribute data elsewhere */ + const struct adata *ptr; /* Attribute data elsewhere */ } u; } eattr; @@ -517,6 +517,8 @@ typedef struct adata { byte data[0]; } adata; +extern const adata null_adata; /* adata of length 0 */ + static inline struct adata * lp_alloc_adata(struct linpool *pool, uint len) { @@ -525,7 +527,7 @@ lp_alloc_adata(struct linpool *pool, uint len) return ad; } -static inline int adata_same(struct adata *a, struct adata *b) +static inline int adata_same(const struct adata *a, const struct adata *b) { return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 3e4578b0..01e807fa 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -58,6 +58,8 @@ #include +const adata null_adata; /* adata of length 0 */ + const char * const rta_src_names[RTS_MAX] = { [RTS_DUMMY] = "", [RTS_STATIC] = "static", @@ -763,7 +765,7 @@ ea_free(ea_list *o) { eattr *a = &o->attrs[i]; if (!(a->type & EAF_EMBEDDED)) - mb_free(a->u.ptr); + mb_free((void *) a->u.ptr); } mb_free(o); } @@ -808,7 +810,7 @@ ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, } static inline void -opaque_format(struct adata *ad, byte *buf, uint size) +opaque_format(const struct adata *ad, byte *buf, uint size) { byte *bound = buf + size - 10; uint i; @@ -831,7 +833,7 @@ opaque_format(struct adata *ad, byte *buf, uint size) } static inline void -ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end) +ea_show_int_set(struct cli *c, const struct adata *ad, int way, byte *pos, byte *buf, byte *end) { int i = int_set_format(ad, way, 0, pos, end - pos); cli_printf(c, -1012, "\t%s", buf); @@ -843,7 +845,7 @@ ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, } static inline void -ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end) +ea_show_ec_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end) { int i = ec_set_format(ad, 0, pos, end - pos); cli_printf(c, -1012, "\t%s", buf); @@ -855,7 +857,7 @@ ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end) } static inline void -ea_show_lc_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end) +ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end) { int i = lc_set_format(ad, 0, pos, end - pos); cli_printf(c, -1012, "\t%s", buf); @@ -882,7 +884,7 @@ ea_show(struct cli *c, eattr *e) { struct protocol *p; int status = GA_UNKNOWN; - struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr; + const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr; byte buf[CLI_MSG_SIZE]; byte *pos = buf, *end = buf + sizeof(buf); @@ -1023,7 +1025,7 @@ ea_hash(ea_list *e) h ^= a->u.data; else { - struct adata *d = a->u.ptr; + const struct adata *d = a->u.ptr; h ^= mem_hash(d->data, d->length); } h *= mul; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index 3af79fd6..b93a423b 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -125,7 +125,7 @@ babel_iface_opt_list: babel_iface: babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish; -dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BABEL_METRIC); } ; +dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_BABEL_METRIC); } ; CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index cbb22038..7c6f2ee9 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -181,7 +181,7 @@ bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size } static int -bgp_put_attr(byte *buf, uint size, uint code, uint flags, byte *data, uint len) +bgp_put_attr(byte *buf, uint size, uint code, uint flags, const byte *data, uint len) { if (size < (4+len)) return -1; @@ -234,15 +234,15 @@ bgp_format_origin(eattr *a, byte *buf, uint size UNUSED) static int bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size) { - byte *data = a->u.ptr->data; + const byte *data = a->u.ptr->data; uint len = a->u.ptr->length; if (!s->as4_session) { /* Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer */ - byte *src = data; - data = alloca(len); - len = as_path_32to16(data, src, len); + byte *dst = alloca(len); + len = as_path_32to16(dst, data, len); + data = dst; } return bgp_put_attr(buf, size, BA_AS_PATH, a->flags, data, len); @@ -381,15 +381,14 @@ bgp_decode_atomic_aggr(struct bgp_parse_state *s, uint code UNUSED, uint flags, static int bgp_encode_aggregator(struct bgp_write_state *s, eattr *a, byte *buf, uint size) { - byte *data = a->u.ptr->data; + const byte *data = a->u.ptr->data; uint len = a->u.ptr->length; if (!s->as4_session) { /* Prepare 16-bit AGGREGATOR (from 32-bit one) in a temporary buffer */ - byte *src = data; - data = alloca(6); - len = aggregator_32to16(data, src); + byte *dst = alloca(6); + len = aggregator_32to16(dst, data); } return bgp_put_attr(buf, size, BA_AGGREGATOR, a->flags, data, len); @@ -415,7 +414,7 @@ bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, b static void bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED) { - byte *data = a->u.ptr->data; + const byte *data = a->u.ptr->data; bsprintf(buf, "%I4 AS%u", get_ip4(data+4), get_u32(data+0)); } @@ -545,12 +544,13 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla static void bgp_export_ext_community(struct bgp_export_state *s, eattr *a) { - a->u.ptr = ec_set_del_nontrans(s->pool, a->u.ptr); + struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr); - if (a->u.ptr->length == 0) + if (ad->length == 0) UNSET(a); - ec_set_sort_x(a->u.ptr); + ec_set_sort_x(ad); + a->u.ptr = ad; } static void @@ -1232,7 +1232,7 @@ bgp_get_bucket(struct bgp_channel *c, ea_list *new) if (!(a->type & EAF_EMBEDDED)) { - struct adata *oa = a->u.ptr; + const struct adata *oa = a->u.ptr; struct adata *na = (struct adata *) dest; memcpy(na, oa, sizeof(struct adata) + oa->length); a->u.ptr = na; @@ -1404,7 +1404,7 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED) if (p->cf->interpret_communities && (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)))) { - struct adata *d = c->u.ptr; + const struct adata *d = c->u.ptr; /* Do not export anywhere */ if (int_set_contains(d, BGP_COMM_NO_ADVERTISE)) @@ -1426,9 +1426,6 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED) return 0; } - -static adata null_adata; /* adata of length 0 */ - static ea_list * bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool) { @@ -1437,7 +1434,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls }; ea_list *attrs = attrs0; eattr *a; - adata *ad; + const adata *ad; /* ORIGIN attribute - mandatory, attach if missing */ if (! bgp_find_attr(attrs0, BA_ORIGIN)) @@ -1962,7 +1959,7 @@ struct rte * bgp_rte_modify_stale(struct rte *r, struct linpool *pool) { eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); - struct adata *ad = a ? a->u.ptr : NULL; + const struct adata *ad = a ? a->u.ptr : NULL; uint flags = a ? a->flags : BAF_PARTIAL; if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR)) @@ -2021,8 +2018,8 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool) return; /* Merge AS_PATH and AS4_PATH */ - as_path_cut(p2->u.ptr, p2_len - p4_len); - p2->u.ptr = as_path_merge(pool, p2->u.ptr, p4->u.ptr); + struct adata *apc = as_path_cut(pool, p2->u.ptr, p2_len - p4_len); + p2->u.ptr = as_path_merge(pool, apc, p4->u.ptr); } } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index cfc88d8e..b604c7aa 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -376,7 +376,7 @@ struct bgp_write_state { int mpls; eattr *mp_next_hop; - adata *mpls_labels; + const adata *mpls_labels; }; struct bgp_parse_state { @@ -507,7 +507,7 @@ bgp_set_attr_u32(ea_list **to, struct linpool *pool, uint code, uint flags, u32 { bgp_set_attr(to, pool, code, flags, (uintptr_t) val); } static inline void -bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, struct adata *val) +bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, const struct adata *val) { bgp_set_attr(to, pool, code, flags, (uintptr_t) val); } static inline void diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index ac8d024a..f9e5efaf 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -272,29 +272,29 @@ bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; dynamic_attr: BGP_ORIGIN - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; dynamic_attr: BGP_PATH - { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, 0, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; dynamic_attr: BGP_NEXT_HOP - { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; dynamic_attr: BGP_MED - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; dynamic_attr: BGP_LOCAL_PREF - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; dynamic_attr: BGP_ATOMIC_AGGR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, 0, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; dynamic_attr: BGP_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; dynamic_attr: BGP_ORIGINATOR_ID - { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; dynamic_attr: BGP_CLUSTER_LIST - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; dynamic_attr: BGP_EXT_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, 0, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; dynamic_attr: BGP_LARGE_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, 0, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 26716573..2b5cc440 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1210,10 +1210,10 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0) } static void -bgp_encode_mpls_labels(struct bgp_write_state *s UNUSED, adata *mpls, byte **pos, uint *size, byte *pxlen) +bgp_encode_mpls_labels(struct bgp_write_state *s UNUSED, const adata *mpls, byte **pos, uint *size, byte *pxlen) { - u32 dummy = 0; - u32 *labels = mpls ? (u32 *) mpls->data : &dummy; + const u32 dummy = 0; + const u32 *labels = mpls ? (const u32 *) mpls->data : &dummy; uint lnum = mpls ? (mpls->length / 4) : 1; for (uint i = 0; i < lnum; i++) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 36fbd5f1..9669b708 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -498,10 +498,10 @@ ospf_iface: ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } ; -dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ; -dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ; -dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ; -dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ; +dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC1); } ; +dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC2); } ; +dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_TAG); } ; +dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ; CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); CF_CLI(SHOW OSPF, optsym, [], [[Show information about OSPF protocol]]) diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 53715f77..b8eeb439 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -332,8 +332,8 @@ radv_sensitive: | SENSITIVE bool { $$ = $2; } ; -dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; -dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ; +dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; +dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RA_LIFETIME); } ; CF_CODE diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 172299d0..265912b2 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -186,8 +186,8 @@ rip_iface: rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish; -dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ; -dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ; +dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_METRIC); } ; +dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_TAG); } ; CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); diff --git a/proto/static/config.Y b/proto/static/config.Y index d7a02961..56caef24 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -14,7 +14,7 @@ CF_DEFINES #define STATIC_CFG ((struct static_config *) this_proto) static struct static_route *this_srt, *this_snh; -static struct f_inst **this_srt_last_cmd; +static struct f_inst *this_srt_cmds, **this_srt_last_cmd; static struct static_route * static_nexthop_new(void) @@ -39,6 +39,8 @@ static_route_finish(void) { if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest) cf_error("Unexpected or missing nexthop/type"); + + this_srt->cmds = f_postfixify(this_srt_cmds); } CF_DECLS @@ -108,7 +110,8 @@ stat_route0: ROUTE net_any { this_srt = cfg_allocz(sizeof(struct static_route)); add_tail(&STATIC_CFG->routes, &this_srt->n); this_srt->net = $2; - this_srt_last_cmd = &(this_srt->cmds); + this_srt_cmds = NULL; + this_srt_last_cmd = &this_srt_cmds; this_srt->mp_next = NULL; this_snh = NULL; } diff --git a/proto/static/static.c b/proto/static/static.c index 75a74ad0..2fa687eb 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -308,7 +308,7 @@ static inline int static_same_rte(struct static_route *or, struct static_route *nr) { /* Note that i_same() requires arguments in (new, old) order */ - return static_same_dest(or, nr) && i_same(nr->cmds, or->cmds); + return static_same_dest(or, nr) && f_same(nr->cmds, or->cmds); } static void diff --git a/proto/static/static.h b/proto/static/static.h index a3c30b87..f736996c 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -39,7 +39,7 @@ struct static_route { struct static_route *chain; /* Next for the same neighbor */ struct static_route *mp_head; /* First nexthop of this route */ struct static_route *mp_next; /* Nexthops for multipath routes */ - struct f_inst *cmds; /* List of commands for setting attributes */ + struct f_line *cmds; /* List of commands for setting attributes */ byte dest; /* Destination type (RTD_*) */ byte state; /* State of route announcement (SRS_*) */ byte active; /* Next hop is active (nbr/iface/BFD available) */ diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 2b8cdaa7..a8af4c95 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -65,27 +65,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N #define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e) #define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f) -/* Bits of EA_KRT_LOCK, also based on RTAX_* constants */ -#define EA_KRT_LOCK_MTU EA_KRT_LOCK | EA_BIT(0x2) -#define EA_KRT_LOCK_WINDOW EA_KRT_LOCK | EA_BIT(0x3) -#define EA_KRT_LOCK_RTT EA_KRT_LOCK | EA_BIT(0x4) -#define EA_KRT_LOCK_RTTVAR EA_KRT_LOCK | EA_BIT(0x5) -#define EA_KRT_LOCK_SSTHRESH EA_KRT_LOCK | EA_BIT(0x6) -#define EA_KRT_LOCK_CWND EA_KRT_LOCK | EA_BIT(0x7) -#define EA_KRT_LOCK_ADVMSS EA_KRT_LOCK | EA_BIT(0x8) -#define EA_KRT_LOCK_REORDERING EA_KRT_LOCK | EA_BIT(0x9) -#define EA_KRT_LOCK_HOPLIMIT EA_KRT_LOCK | EA_BIT(0xa) -// define EA_KRT_LOCK_INITCWND EA_KRT_LOCK | EA_BIT(0xb) -// define EA_KRT_LOCK_FEATURES EA_KRT_LOCK | EA_BIT(0xc) -#define EA_KRT_LOCK_RTO_MIN EA_KRT_LOCK | EA_BIT(0xd) -// define EA_KRT_LOCK_INITRWND EA_KRT_LOCK | EA_BIT(0xe) - -/* Bits of EA_KRT_FEATURES, based on RTAX_FEATURE_* constants */ -#define EA_KRT_FEATURE_ECN EA_KRT_FEATURES | EA_BIT(0x0) -// define EA_KRT_FEATURE_SACK EA_KRT_FEATURES | EA_BIT(0x1) -// define EA_KRT_FEATURE_TSTAMP EA_KRT_FEATURES | EA_BIT(0x2) -#define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3) - struct krt_params { u32 table_id; /* Kernel table ID we sync with */ diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index 1030e5d4..8f0a91c1 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -26,37 +26,39 @@ kern_sys_item: | METRIC expr { THIS_KRT->sys.metric = $2; } ; -dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ; -dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ; -dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ; +dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_KRT_PREFSRC); } ; +dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REALM); } ; +dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SCOPE); } ; -dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ; -dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ; -dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ; -dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ; -dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ; -dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ; -dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ; -dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ; -dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ; -dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ; -dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ; -dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ; -dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ; +dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_MTU); } ; +dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_WINDOW); } ; +dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTT); } ; +dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTTVAR); } ; +dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SSTRESH); } ; +dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_CWND); } ; +dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_ADVMSS); } ; +dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REORDERING); } ; +dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_HOPLIMIT); } ; +dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITCWND); } ; +dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTO_MIN); } ; +dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITRWND); } ; +dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_QUICKACK); } ; -dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_MTU); } ; -dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_WINDOW); } ; -dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTT); } ; -dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTTVAR); } ; -dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_SSTHRESH); } ; -dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_CWND); } ; -dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_ADVMSS); } ; -dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_REORDERING); } ; -dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_HOPLIMIT); } ; -dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTO_MIN); } ; +/* Bits of EA_KRT_LOCK, based on RTAX_* constants */ -dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ECN); } ; -dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ALLFRAG); } ; +dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 2, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 4, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 5, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 6, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 7, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 8, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 9, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 10, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 13, T_BOOL, EA_KRT_LOCK); } ; + +dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 0, T_BOOL, EA_KRT_FEATURES); } ; +dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_FEATURES); } ; CF_CODE diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index d773743d..e21f4039 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1719,9 +1719,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) ea->attrs[0].id = EA_KRT_PREFSRC; ea->attrs[0].flags = 0; ea->attrs[0].type = EAF_TYPE_IP_ADDRESS; - ea->attrs[0].u.ptr = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps)); - ea->attrs[0].u.ptr->length = sizeof(ps); - memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps)); + + struct adata *ad = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps)); + ad->length = sizeof(ps); + memcpy(ad->data, &ps, sizeof(ps)); + + ea->attrs[0].u.ptr = ad; } if (a[RTA_FLOW]) diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 95b54d65..e3f6271c 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -122,8 +122,8 @@ kif_iface: kif_iface_start iface_patt_list_nopx kif_iface_opt_list; -dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SOURCE); } ; -dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_METRIC); } ; +dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SOURCE); } ; +dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_METRIC); } ; CF_CODE From 9b46748d5b50d1e8c242a571e80fe1f9f33aeb73 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 21 Jan 2019 09:17:54 +0100 Subject: [PATCH 17/88] Filter: refactoring of instruction constructors --- conf/conf.h | 2 +- conf/confbase.Y | 4 + filter/Makefile | 10 +- filter/config.Y | 343 ++++++++++++++++++------------------------ filter/dump.m4 | 4 +- filter/f-inst.c | 101 +++++++++---- filter/f-inst.h | 124 +++++++++++++++ filter/f-util.c | 98 ++++++------ filter/filter.c | 30 ++-- filter/filter.h | 232 ++++++++++++++-------------- filter/interpret.m4 | 11 +- filter/line-size.m4 | 14 +- filter/new.m4 | 84 +++++++++++ filter/postfixify.m4 | 39 +++-- filter/same.m4 | 4 +- filter/struct.m4 | 67 +++++++++ nest/attrs.h | 2 +- proto/static/config.Y | 12 +- 18 files changed, 749 insertions(+), 432 deletions(-) create mode 100644 filter/f-inst.h create mode 100644 filter/new.m4 create mode 100644 filter/struct.m4 diff --git a/conf/conf.h b/conf/conf.h index 427569fd..6138ccec 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -107,7 +107,7 @@ struct symbol { struct sym_scope *scope; int class; int aux; - void *aux2; + uint aux2; void *def; char name[1]; }; diff --git a/conf/confbase.Y b/conf/confbase.Y index 492ecd08..13f6aade 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -49,6 +49,10 @@ CF_DECLS struct rtable_config *r; struct channel_config *cc; struct f_inst *x; + struct f_inst *xp[2]; + struct { struct f_inst *inst; uint count; } xc; + enum filter_return fret; + enum ec_subtype ecs; struct f_dynamic_attr fda; struct f_static_attr fsa; struct filter *f; diff --git a/filter/Makefile b/filter/Makefile index c74ba2f3..15f2c3d0 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,4 +1,4 @@ -src := filter.c f-util.c tree.c trie.c +src := filter.c f-util.c tree.c trie.c f-inst-new.c obj := $(src-o-files) $(all-daemon) $(cf-local) @@ -17,10 +17,16 @@ $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ +$(o)f-inst-struct.h: $(s)struct.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + +$(o)f-inst-new.c: $(s)new.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ + $(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)f-inst-struct.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/config.Y b/filter/config.Y index a79b1582..607f534e 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -16,6 +16,8 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } +#define f_generate_complex(fi_code, da, arg) \ + f_new_inst(FI_EA_SET, da, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg)) /* * Sets and their items are during parsing handled as lists, linked @@ -158,30 +160,29 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) static inline struct f_inst * f_generate_empty(struct f_dynamic_attr dyn) { - struct f_inst *e = f_new_inst(FI_CONSTANT); + struct f_val empty; switch (dyn.type & EAF_TYPE_MASK) { case EAF_TYPE_AS_PATH: - e->val = f_const_empty_path; + empty = f_const_empty_path; break; case EAF_TYPE_INT_SET: - e->val = f_const_empty_clist; + empty = f_const_empty_clist; break; case EAF_TYPE_EC_SET: - e->val = f_const_empty_eclist; + empty = f_const_empty_eclist; break; case EAF_TYPE_LC_SET: - e->val = f_const_empty_lclist; + empty = f_const_empty_lclist; break; default: cf_error("Can't empty that attribute"); } - struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn); - s->a[0].p = e; - return s; + return f_new_inst(FI_EA_SET, dyn, f_new_inst(FI_CONSTANT, empty)); } +#if 0 static inline struct f_inst * f_generate_dpair(struct f_inst *t1, struct f_inst *t2) @@ -332,6 +333,8 @@ f_generate_path_mask(struct f_inst *t) return pmc; } +#endif + /* * Remove all new lines and doubled whitespaces * and convert all tabulators to spaces @@ -380,21 +383,10 @@ assert_copy_expr(const char *start, size_t len) 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->a[0].p = expr; - - if (end >= start) - { - i->a[1].p = assert_copy_expr(start, end - start + 1); - } - else - { - /* this is a break of lexer buffer */ - i->a[1].p = "???"; - } - - return i; + return f_new_inst(FI_ASSERT, expr, + (end >= start) ? + assert_copy_expr(start, end - start + 1) + : "???"); } CF_DECLS @@ -420,17 +412,20 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc THEN %nonassoc ELSE -%type term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail +%type function_params declsn +%type cmds_int function_body +%type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail one_decl decls %type dynamic_attr %type static_attr %type filter filter_body where_filter -%type type break_command ec_kind +%type type +%type ec_kind +%type break_command %type cnum %type pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body %type fprefix_set %type set_atom switch_atom fipa %type fprefix -%type decls declsn one_decl function_params %type get_cf_position CF_GRAMMAR @@ -515,8 +510,7 @@ one_decl: val->type = T_VOID; $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); DBG( "New variable %s type %x\n", $2->name, $1 ); - $2->aux2 = NULL; - $$=$2; + $$ = f_new_inst(FI_SET, NULL, $2); } ; @@ -524,24 +518,29 @@ one_decl: decls: /* EMPTY */ { $$ = NULL; } | one_decl ';' decls { $$ = $1; - $$->aux2 = $3; + f_inst_next($$, $3); } ; -/* Declarations that have no ';' at the end. */ -declsn: one_decl { $$ = $1; } +/* Declarations that have no ';' at the end. Beware; these are reversed. */ +declsn: one_decl { $$.inst = $1; $$.count = 1; } | one_decl ';' declsn { - $$ = $1; - $$->aux2 = $3; + $$ = $3; + $$.count++; + f_inst_next($$.inst, $1); } ; filter_body: function_body { - struct filter *f = cfg_alloc(sizeof(struct filter)); - f->name = NULL; - f->root = f_postfixify($1); - $$ = f; + $$ = cfg_alloc(sizeof(struct filter)); + $$->name = NULL; + if ($1[0]) { + const struct f_inst *inst[2] = { $1[0], $1[1] }; + $$->root = f_postfixify_concat(inst, 2); + } + else + $$->root = f_postfixify($1[1]); } ; @@ -556,42 +555,19 @@ filter: where_filter: WHERE term { /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ - struct filter *f = cfg_alloc(sizeof(struct filter)); - struct f_inst acc = { - .fi_code = FI_PRINT_AND_DIE, - .a = { { .p = NULL }, { .i = F_ACCEPT } }, - .lineno = ifs->lino, - }; - struct f_inst rej = { - .fi_code = FI_PRINT_AND_DIE, - .a = { { .p = NULL }, { .i = F_REJECT } }, - .lineno = ifs->lino, - }; - struct f_inst i = { - .fi_code = FI_CONDITION, - .a = { { .p = $2 }, { .p = &acc }, { .p = &rej } }, - .lineno = ifs->lino, - }; - f->name = NULL; - f->root = f_postfixify(&i); - $$ = f; + $$ = f_new_where($2); } ; function_params: - '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } - | '(' ')' { $$=NULL; } + '(' declsn ')' { $$ = $2; } + | '(' ')' { $$.inst = NULL; $$.count = 0; } ; function_body: decls '{' cmds '}' { - if ($1) { - /* Prepend instruction to clear local variables */ - $$ = f_new_inst(FI_CLEAR_LOCAL_VARS); - $$->a[0].p = $1; - $$->next = $3; - } else - $$ = $3; + $$[0] = $1 ? f_clear_local_vars($1) : NULL; + $$[1] = $3; } ; @@ -601,10 +577,26 @@ function_def: $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); cf_push_scope($2); } function_params function_body { - struct f_inst *vc = f_new_inst(FI_CONSTANT); - vc->val = (struct f_val) { .type = T_VOID }; - $2->def = f_postfixify_concat($5, vc, NULL); - $2->aux2 = $4; + const struct f_inst *catlist[4]; + uint count = 0; + + /* Argument setters */ + if ($4.inst) + catlist[count++] = $4.inst; + + /* Local var clearers */ + if ($5[0]) + catlist[count++] = $5[0]; + + /* Return void if no return is needed */ + catlist[count++] = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); + + /* Function body itself */ + if ($5[1]) + catlist[count++] = $5[1]; + + $2->def = f_postfixify_concat(catlist, count); + $2->aux2 = $4.count; DBG("Hmm, we've got one function here - %s\n", $2->name); cf_pop_scope(); } @@ -612,15 +604,12 @@ function_def: /* Programs */ -/* Hack: $$ of cmds_int is the last node. - $$->next of cmds_int is temporary used for the first node */ - cmds: /* EMPTY */ { $$ = NULL; } - | cmds_int { $$ = $1->next; $1->next = NULL; } + | cmds_int { $$ = $1[0]; } ; -cmds_int: cmd { $$ = $1; $1->next = $1; } - | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; } +cmds_int: cmd { $$[0] = $$[1] = $1; } + | cmds_int cmd { $$[1] = $2; f_inst_next($1[1], $2); $$[0] = $1[0]; } ; block: @@ -784,37 +773,36 @@ bgp_path: ; bgp_path_tail: - NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; } - | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; } - | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; } - | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; } - | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; } + NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); f_inst_next($$, $2); } + | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); f_inst_next($$, $4); } + | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); f_inst_next($$, $2); } + | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); f_inst_next($$, $2); } + | bgp_path_expr bgp_path_tail { $$ = $1; f_inst_next($$, $2); } | { $$ = NULL; } ; constant: - NUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_INT, .val.i = $1, }; } - | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 1, }; } - | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 0, }; } - | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_STRING, .val.s = $1, }; } - | fipa { $$ = f_new_inst(FI_CONSTANT); $$->val = $1; } - | VPN_RD { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_RD, .val.ec = $1, }; } - | net_ { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_NET, .val.net = $1, }; } + NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); } + | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); } + | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); } + | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); } + | fipa { $$ = f_new_inst(FI_CONSTANT, $1); } + | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); } + | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); } | '[' set_items ']' { DBG( "We've got a set here..." ); - $$ = f_new_inst(FI_CONSTANT); - $$->val = (struct f_val) { .type = T_SET, .val.t = build_tree($2), }; + $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), }); DBG( "ook\n" ); } - | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }; } - | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }; } + | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); } + | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } ; constructor: - '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } - | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } - | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } - | bgp_path { $$ = f_generate_path_mask($1); } + '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } + | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } + | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); } + | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); } ; @@ -823,23 +811,7 @@ rtadot: /* EMPTY, we are not permitted RTA. prefix */ function_call: SYM '(' var_list ')' { - struct symbol *sym; - struct f_inst *inst = $3; - if ($1->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); - DBG("You are calling function %s\n", $1->name); - $$ = f_new_inst(FI_CALL); - $$->a[0].p = inst; - $$->a[1].p = $1->def; - sym = $1->aux2; - while (sym || inst) { - if (!sym || !inst) - cf_error("Wrong number of arguments for function %s.", $1->name); - DBG( "You should pass parameter called %s\n", sym->name); - inst->a[0].p = sym; - sym = sym->aux2; - inst = inst->next; - } + $$ = f_new_inst(FI_CALL, $1, $3); } ; @@ -847,15 +819,13 @@ symbol: SYM { switch ($1->class & 0xffff) { case SYM_CONSTANT_RANGE: - $$ = f_new_inst(FI_CONSTANT_INDIRECT); - $$->a[0].p = $1; + $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); break; case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VARIABLE); - $$->a[0].p = $1; + $$ = f_new_inst(FI_VARIABLE, $1); break; case SYM_ATTRIBUTE: - $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); + $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); break; default: cf_error("%s: variable expected.", $1->name); @@ -876,22 +846,22 @@ static_attr: term: '(' term ')' { $$ = $2; } - | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; } - | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; } - | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; } - | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; } - | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; } - | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; } - | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; } - | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; } - | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; } - | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; } - | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; } + | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); } + | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); } + | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); } + | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); } + | term AND term { $$ = f_new_inst(FI_AND, $1, $3); } + | term OR term { $$ = f_new_inst(FI_OR, $1, $3); } + | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); } + | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); } + | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); } + | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); } + | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); } + | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); } + | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); } + | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); } + | '!' term { $$ = f_new_inst(FI_NOT, $2); } + | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); } | symbol { $$ = $1; } | constant { $$ = $1; } @@ -899,22 +869,22 @@ term: | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); } - | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); } + | rtadot static_attr { $$ = f_new_inst(FI_RTA_GET, $2); } - | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); } + | rtadot dynamic_attr { $$ = f_new_inst(FI_EA_GET, $2); } - | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; } - | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; } - | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; } - | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; } - | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; } - | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; } - | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; } - | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; } - | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; } - | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; } - | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; } - | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; } + | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); } + | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); } + | term '.' IP { $$ = f_new_inst(FI_IP, $1); } + | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); } + | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); } + | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); } + | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); } + | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); } + | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); } + | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); } + | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); } + | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); } /* Communities */ /* This causes one shift/reduce conflict @@ -924,19 +894,19 @@ term: | rtadot dynamic_attr '.' RESET{ } */ - | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; } - | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; } - | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; } - | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; } - | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; } - | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; } - | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; } - | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; } + | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); } + | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); } + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); } + | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); } + | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); } + | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); } + | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); } - | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; } - | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; } + | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); } - | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; } + | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); } /* | term '.' LEN { $$->code = P('P','l'); } */ @@ -953,30 +923,25 @@ break_command: ; print_one: - term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; } + term { $$ = f_new_inst(FI_PRINT, $1); } ; print_list: /* EMPTY */ { $$ = NULL; } | print_one { $$ = $1; } | print_one ',' print_list { if ($1) { - $1->next = $3; + f_inst_next($1, $3); $$ = $1; } else $$ = $3; } ; var_listn: term { - $$ = f_new_inst(FI_SET); - $$->a[0].p = NULL; - $$->a[1].p = $1; - $$->next = NULL; + $$ = $1; } | term ',' var_listn { - $$ = f_new_inst(FI_SET); - $$->a[0].p = NULL; - $$->a[1].p = $1; - $$->next = $3; + $$ = $1; + f_inst_next($$, $3); } ; @@ -986,58 +951,42 @@ var_list: /* EMPTY */ { $$ = NULL; } cmd: IF term THEN block { - $$ = f_new_inst(FI_CONDITION); - $$->a[0].p = $2; - $$->a[1].p = $4; + $$ = f_new_inst(FI_CONDITION, $2, $4, NULL); } | IF term THEN block ELSE block { - $$ = f_new_inst(FI_CONDITION); - $$->a[0].p = $2; - $$->a[1].p = $4; - $$->a[2].p = $6; + $$ = f_new_inst(FI_CONDITION, $2, $4, $6); } | SYM '=' term ';' { DBG( "Ook, we'll set value\n" ); if ($1->class == SYM_ATTRIBUTE) { - $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def)); - $$->a[0].p = $3; + $$ = f_new_inst(FI_EA_SET, *((struct f_dynamic_attr *) $1->def), $3); } else if (($1->class & ~T_MASK) == SYM_VARIABLE) { - $$ = f_new_inst(FI_SET); - $$->a[0].p = $1; - $$->a[1].p = $3; + $$ = f_new_inst(FI_SET, $3, $1); } else cf_error( "Symbol `%s' is read-only.", $1->name ); } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); - $$ = f_new_inst(FI_RETURN); - $$->a[0].p = $2; + $$ = f_new_inst(FI_RETURN, $2); } | rtadot dynamic_attr '=' term ';' { - $$ = f_new_inst_da(FI_EA_SET, $2); - $$->a[0].p = $4; + $$ = f_new_inst(FI_EA_SET, $2, $4); } | rtadot static_attr '=' term ';' { - $$ = f_new_inst_sa(FI_RTA_SET, $2); - if ($$->sa.readonly) + if ($2.readonly) cf_error( "This static attribute is read-only."); - $$->a[0].p = $4; + $$ = f_new_inst(FI_RTA_SET, $2, $4); } | PREFERENCE '=' term ';' { - $$ = f_new_inst(FI_PREF_SET); - $$->a[0].p = $3; + $$ = f_new_inst(FI_PREF_SET, $3); } | UNSET '(' rtadot dynamic_attr ')' ';' { - $$ = f_new_inst_da(FI_EA_SET, $4); - $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; - $$->a[0].p = NULL; + $$ = f_new_inst(FI_EA_UNSET, $4); } - | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; } - | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; } + | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); } + | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } | CASE term '{' switch_body '}' { - $$ = f_new_inst(FI_SWITCH); - $$->a[0].p = $2; - $$->a[1].p = build_tree( $4 ); + $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); } | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } diff --git a/filter/dump.m4 b/filter/dump.m4 index 913a7652..cb8e5c5f 100644 --- a/filter/dump.m4 +++ b/filter/dump.m4 @@ -17,9 +17,9 @@ m4_divert(-1)') m4_define(LINEP, `LINE($@)') m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name); m4_divert(-1)') -m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp)); +m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(&item->val)); m4_divert(-1)') -m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp)); +m4_define(VAR, `m4_divert(1)debug("%svar %s: value %s\n", INDENT, item->sym->name, val_dump(item->vp)); m4_divert(-1)') m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret); m4_divert(-1)') diff --git a/filter/f-inst.c b/filter/f-inst.c index 02c88409..ae2b5289 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -108,6 +108,17 @@ INST(FI_PATHMASK_CONSTRUCT, 0, 1) { ARG_ANY(1); COUNT(2); + + NEW([[]], [[ + uint len = 0; + uint dyn = 0; + for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) + if (tt->fi_code != FI_CONSTANT) + dyn++; + + WHAT().count = len; + ]]); + if (vstk.cnt < what->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count); @@ -239,13 +250,11 @@ RESULT_OK; } INST(FI_VARIABLE, 0, 1) { - VALP(1); // res = * ((struct f_val *) what->a[0].p); - SAME([[if (strcmp(f1->sym->name, f2->sym->name)) return 0; ]]); + VAR; RESULT_OK; } INST(FI_CONSTANT_INDIRECT, 0, 1) { - VALP(1); - SAME([[if (!val_same(f1->vp, f2->vp)) return 0; ]]); + VALP; RESULT_OK; } INST(FI_PRINT, 1, 0) { @@ -261,15 +270,16 @@ } INST(FI_PRINT_AND_DIE, 0, 0) { POSTFIXIFY([[ - if (what->a[0].p) { - pos = postfixify(dest, what->a[0].p, pos); - dest->items[pos].flags |= FIF_PRINTED; - } + { + uint opos = pos; ]]); - LINE_SIZE([[ - if (what->a[0].p) { - cnt += inst_line_size(what->a[0].p); - } + + ARG_ANY(1); + + POSTFIXIFY([[ + if (opos < pos) + dest->items[pos].flags |= FIF_PRINTED; + } ]]); FRET(2); @@ -544,11 +554,6 @@ runtime( "Setting lclist attribute to non-lclist value" ); l->attrs[0].u.ptr = v1.val.ad; break; - case EAF_TYPE_UNDEF: - if (v1.type != T_VOID) - runtime( "Setting void attribute to non-void value" ); - l->attrs[0].u.data = 0; - break; default: bug("Unknown type in e,S"); } @@ -558,6 +563,28 @@ } } + INST(FI_EA_UNSET, 0, 0) { + DYNAMIC_ATTR; + ACCESS_RTE; + ACCESS_EATTRS; + + { + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + + l->next = NULL; + l->flags = EALF_SORTED; + l->count = 1; + l->attrs[0].id = da.ea_code; + l->attrs[0].flags = 0; + l->attrs[0].type = EAF_TYPE_UNDEF | EAF_TEMP | EAF_ORIGINATED | EAF_FRESH; + l->attrs[0].u.data = 0; + + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; + } + } + INST(FI_PREF_GET, 0, 1) { ACCESS_RTE; RESULT(T_INT, i, (*fs->rte)->pref); @@ -660,6 +687,7 @@ if (!estk.cnt) if (vstk.val[retpos].type == T_BOOL) if (vstk.val[retpos].val.i) + return F_ACCEPT; else return F_REJECT; @@ -674,28 +702,43 @@ } INST(FI_CALL, 0, 1) { - /* First push the code */ - LINEP(2,0); + /* Do not use the symbol on execution */ + if (0) { + UNUSED SYMBOL; + } + + /* Postfixify extracts the function body from the symbol */ + POSTFIXIFY([[ + dest->items[pos].lines[0] = what->sym->def; + ]]); + + /* First push the body on stack */ + LINEX(what->lines[0]); curline.emask |= FE_RETURN; /* Then push the arguments */ LINE(1,1); + + NEW([[]], [[ + if (sym->class != SYM_FUNCTION) + cf_error("You can't call something which is not a function. Really."); + + uint count = 0; + for (const struct f_inst *inst = f1; inst; inst = inst->next) + count++; + + if (count != sym->aux2) + cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); + ]]); } INST(FI_DROP_RESULT, 1, 0) { ARG_ANY(1); } - INST(FI_CLEAR_LOCAL_VARS, 0, 0) { /* Clear local variables */ - SYMBOL(1); - for ( ; sym != NULL; sym = sym->aux2) - ((struct f_val *) sym->def)->type = T_VOID; - } INST(FI_SWITCH, 1, 0) { ARG_ANY(1); - POSTFIXIFY([[ - dest->items[pos].tree = what->a[1].p; - ]]); + TREE; const struct f_tree *t = find_tree(what->tree, &v1); if (!t) { v1.type = T_VOID; @@ -940,8 +983,6 @@ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ ARG(1, T_BOOL); - POSTFIXIFY([[ - dest->items[pos].s = what->a[1].p; - ]]); + STRING; CALL(bt_assert_hook, res.val.i, what); } diff --git a/filter/f-inst.h b/filter/f-inst.h new file mode 100644 index 00000000..5c3d1d58 --- /dev/null +++ b/filter/f-inst.h @@ -0,0 +1,124 @@ +/* + * BIRD Internet Routing Daemon -- Filter instructions + * + * (c) 2018--2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +/* Filter instruction words */ +#define FI__TWOCHAR(a,b) ((a<<8) | b) +#define FI__LIST \ + F(FI_NOP, 0, '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_PATHMASK_CONSTRUCT, 'm', 'P') \ + 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_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_SADR_SRC, 'n', 's') \ + 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_DROP_RESULT, 'd', 'r') \ + F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \ + F(FI_SWITCH, 'S', 'W') \ + F(FI_IP_MASK, 'i', 'M') \ + F(FI_PATH_PREPEND, 'A', 'p') \ + F(FI_CLIST_ADD, 'C', 'a') \ + F(FI_CLIST_DEL, 'C', 'd') \ + F(FI_CLIST_FILTER, 'C', 'f') \ + F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \ + F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \ + F(FI_FORMAT, 0, 'F') \ + F(FI_ASSERT, 'a', 's') + +/* The enum itself */ +enum f_instruction_code { +#define F(c,a,b) \ + c, +FI__LIST +#undef F + FI__MAX, +} PACKED; + +/* Convert the instruction back to the enum name */ +const char *f_instruction_name(enum f_instruction_code fi); + + + +/* Instruction structure for config */ +struct f_inst { + const struct f_inst *next; /* Next instruction to be executed */ + union { /* Instruction content */ + struct { /* Instruction code for dispatching purposes */ + enum f_instruction_code fi_code; + }; + + struct { + enum f_instruction_code fi_code_a; + const struct f_inst *p[3]; /* Three arguments at most */ + }; + + struct { + + + + struct { + enum f_instruction_code + + + + + enum f_iknst + u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ + union { + + union f_inst_attr a[3]; /* The three arguments */ + struct f_val val; /* The value if FI_CONSTANT */ + struct { + union f_inst_attr sa_a[1]; + struct f_static_attr sa; /* Static attribute def for FI_RTA_* */ + }; + struct { + union f_inst_attr da_a[1]; + struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */ + }; + }; + int lineno; +}; + diff --git a/filter/f-util.c b/filter/f-util.c index 4f11a6d9..e94331b6 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -10,57 +10,15 @@ #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-inst-struct.h" #include "lib/idm.h" #include "nest/protocol.h" #include "nest/route.h" #define P(a,b) ((a<<8) | b) -struct f_inst * -f_new_inst(enum f_instruction_code fi_code) -{ - struct f_inst * ret; - ret = cfg_allocz(sizeof(struct f_inst)); - ret->fi_code = fi_code; - ret->lineno = ifs->lino; - return ret; -} - -struct f_inst * -f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da) -{ - struct f_inst *ret = f_new_inst(fi_code); - ret->da = da; - 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->sa = sa; - return ret; -} - -/* - * Generate set_dynamic( operation( get_dynamic(), argument ) ) - */ -struct f_inst * -f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument) -{ - struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da), - *oper = f_new_inst(fi_code), - *get_dyn = f_new_inst_da(FI_EA_GET, da); - - oper->a[0].p = get_dyn; - oper->a[1].p = argument; - - set_dyn->a[0].p = oper; - return set_dyn; -} - static const char * const f_instruction_name_str[] = { -#define F(c,a,b) \ +#define F(c,...) \ [c] = #c, FI__LIST #undef F @@ -88,6 +46,58 @@ filter_name(struct filter *filter) return filter->name; } +void f_inst_next(struct f_inst *first, const struct f_inst *append) +{ + first->next = append; +} + +struct filter *f_new_where(const struct f_inst *where) +{ + struct f_inst acc = { + .fi_code = FI_PRINT_AND_DIE, + .lineno = ifs->lino, + .i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, }, + }; + + struct f_inst rej = { + .fi_code = FI_PRINT_AND_DIE, + .lineno = ifs->lino, + .i_FI_PRINT_AND_DIE = { .fret = F_REJECT, }, + }; + + struct f_inst i = { + .fi_code = FI_CONDITION, + .lineno = ifs->lino, + .i_FI_CONDITION = { + .f1 = where, + .f2 = &acc, + .f3 = &rej, + }, + }; + + struct filter *f = cfg_alloc(sizeof(struct filter)); + f->name = NULL; + f->root = f_postfixify(&i); + return f; +} + +struct f_inst *f_clear_local_vars(struct f_inst *decls) +{ + /* Prepend instructions to clear local variables */ + struct f_inst *head = NULL; + + for (const struct f_inst *si = decls; si; si = si->next) { + struct f_inst *cur = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); + if (head) + f_inst_next(cur, head); + else + f_inst_next(cur, si); + head = cur; /* The first FI_CONSTANT put there */ + } + + return head; +} + #define CA_KEY(n) n->name, n->fda.type #define CA_NEXT(n) n->next #define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb)) diff --git a/filter/filter.c b/filter/filter.c index 858d5fc5..a69d1b3d 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -47,6 +47,7 @@ #include "nest/attrs.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-inst-struct.h" #define CMP_ERROR 999 @@ -614,11 +615,11 @@ val_format_str(struct filter_state *fs, struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; static uint -inst_line_size(const struct f_inst *what) +inst_line_size(const struct f_inst *what_) { uint cnt = 0; - for ( ; what; what = what->next) { - switch (what->fi_code) { + for ( ; what_; what_ = what_->next) { + switch (what_->fi_code) { #include "filter/f-inst-line-size.c" } } @@ -671,10 +672,10 @@ f_dump_line(const struct f_line *dest, int indent) #endif static uint -postfixify(struct f_line *dest, const struct f_inst *what, uint pos) +postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) { - for ( ; what; what = what->next) { - switch (what->fi_code) { + for ( ; what_; what_ = what_->next) { + switch (what_->fi_code) { #include "filter/f-inst-postfixify.c" } pos++; @@ -683,23 +684,16 @@ postfixify(struct f_line *dest, const struct f_inst *what, uint pos) } struct f_line * -f_postfixify_concat(struct f_inst *first, ...) +f_postfixify_concat(const struct f_inst * const inst[], uint count) { - va_list args; - va_list argd; - va_start(args, first); - va_copy(argd, args); - uint len = 0; - for (struct f_inst *what = first; what; what = va_arg(args, struct f_inst *)) - len += inst_line_size(what); - - va_end(args); + for (uint i=0; ilen = postfixify(out, what, out->len); + for (uint i=0; ilen = postfixify(out, inst[i], out->len); f_dump_line(out, 0); return out; diff --git a/filter/filter.h b/filter/filter.h index 87bd2c36..39f16e93 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -2,6 +2,7 @@ * BIRD Internet Routing Daemon -- Filters * * (c) 1999 Pavel Machek + * (c) 2018--2019 Maria Matejka * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -11,6 +12,7 @@ #include "lib/resource.h" #include "lib/ip.h" +#include "lib/macro.h" #include "nest/route.h" #include "nest/attrs.h" @@ -115,109 +117,6 @@ struct f_static_attr { int readonly:1; /* Don't allow writing */ }; -/* Filter instruction words */ -#define FI__TWOCHAR(a,b) ((a<<8) | b) -#define FI__LIST \ - F(FI_NOP, 0, '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_PATHMASK_CONSTRUCT, 'm', 'P') \ - 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_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_SADR_SRC, 'n', 's') \ - 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_DROP_RESULT, 'd', 'r') \ - F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \ - F(FI_SWITCH, 'S', 'W') \ - F(FI_IP_MASK, 'i', 'M') \ - F(FI_PATH_PREPEND, 'A', 'p') \ - F(FI_CLIST_ADD, 'C', 'a') \ - F(FI_CLIST_DEL, 'C', 'd') \ - F(FI_CLIST_FILTER, 'C', 'f') \ - F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \ - F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \ - F(FI_FORMAT, 0, 'F') \ - F(FI_ASSERT, 'a', 's') - -/* The enum itself */ -enum f_instruction_code { -#define F(c,a,b) \ - c, -FI__LIST -#undef F - FI__MAX, -} PACKED; - -/* Convert the instruction back to the enum name */ -const char *f_instruction_name(enum f_instruction_code fi); - -enum f_instruction_flags { - FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ -}; - -union f_inst_attr { - uint i; - void *p; - struct rtable_config *rtc; -}; - -/* Instruction structure for config */ -struct f_inst { - struct f_inst *next; /* Next instruction to be executed */ - enum f_instruction_code fi_code; /* The instruction itself */ - u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ - union { - union f_inst_attr a[3]; /* The three arguments */ - struct f_val val; /* The value if FI_CONSTANT */ - struct { - union f_inst_attr sa_a[1]; - struct f_static_attr sa; /* Static attribute def for FI_RTA_* */ - }; - struct { - union f_inst_attr da_a[1]; - struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */ - }; - }; - int lineno; -}; - /* Possible return values of filter execution */ enum filter_return { F_NOP = 0, @@ -229,6 +128,121 @@ enum filter_return { F_QUITBIRD, }; +/* Filter instruction declarations */ +#define FI__LIST \ + F(FI_NOP) \ + F(FI_ADD, ARG, ARG) \ + F(FI_SUBTRACT, ARG, ARG) \ + F(FI_MULTIPLY, ARG, ARG) \ + F(FI_DIVIDE, ARG, ARG) \ + F(FI_AND, ARG, LINE) \ + F(FI_OR, ARG, LINE) \ + F(FI_PAIR_CONSTRUCT, ARG, ARG) \ + F(FI_EC_CONSTRUCT, ARG, ARG, ECS) \ + F(FI_LC_CONSTRUCT, ARG, ARG, ARG) \ + F(FI_PATHMASK_CONSTRUCT, ARG, COUNT) \ + F(FI_NEQ, ARG, ARG) \ + F(FI_EQ, ARG, ARG) \ + F(FI_LT, ARG, ARG) \ + F(FI_LTE, ARG, ARG) \ + F(FI_NOT, ARG) \ + F(FI_MATCH, ARG, ARG) \ + F(FI_NOT_MATCH, ARG, ARG) \ + F(FI_DEFINED, ARG) \ + F(FI_TYPE, ARG) \ + F(FI_IS_V4, ARG) \ + F(FI_SET, ARG, SYMBOL) \ + F(FI_CONSTANT, VALI) \ + F(FI_VARIABLE, SYMBOL) \ + F(FI_CONSTANT_INDIRECT, VALP) \ + F(FI_PRINT, ARG) \ + F(FI_CONDITION, ARG, LINE, LINE) \ + F(FI_PRINT_AND_DIE, ARG, FRET) \ + F(FI_RTA_GET, SA) \ + F(FI_RTA_SET, SA, ARG) \ + F(FI_EA_GET, EA) \ + F(FI_EA_SET, EA, ARG) \ + F(FI_EA_UNSET, EA) \ + F(FI_PREF_GET) \ + F(FI_PREF_SET, ARG) \ + F(FI_LENGTH, ARG) \ + F(FI_ROA_MAXLEN, ARG) \ + F(FI_ROA_ASN, ARG) \ + F(FI_SADR_SRC, ARG) \ + F(FI_IP, ARG) \ + F(FI_ROUTE_DISTINGUISHER, ARG) \ + F(FI_AS_PATH_FIRST, ARG) \ + F(FI_AS_PATH_LAST, ARG) \ + F(FI_AS_PATH_LAST_NAG, ARG) \ + F(FI_RETURN, ARG) \ + F(FI_CALL, SYMBOL, LINE) \ + F(FI_DROP_RESULT, ARG) \ + F(FI_SWITCH, ARG, TREE) \ + F(FI_IP_MASK, ARG, ARG) \ + F(FI_PATH_PREPEND, ARG, ARG) \ + F(FI_CLIST_ADD, ARG, ARG) \ + F(FI_CLIST_DEL, ARG, ARG) \ + F(FI_CLIST_FILTER, ARG, ARG) \ + F(FI_ROA_CHECK_IMPLICIT, RTC) \ + F(FI_ROA_CHECK_EXPLICIT, ARG, ARG, RTC) \ + F(FI_FORMAT, ARG) \ + F(FI_ASSERT, ARG, STRING) + +/* The enum itself */ +enum f_instruction_code { +#define F(c, ...) c, +FI__LIST +#undef F + FI__MAX, +} PACKED; + +/* Convert the instruction back to the enum name */ +const char *f_instruction_name(enum f_instruction_code fi); + +struct f_inst; +void f_inst_next(struct f_inst *first, const struct f_inst *append); +struct f_inst *f_clear_local_vars(struct f_inst *decls); + +#define FIA(x) , FIA_##x +#define FIA_ARG const struct f_inst * +#define FIA_LINE const struct f_inst * +#define FIA_COUNT uint +#define FIA_SYMBOL const struct symbol * +#define FIA_VALI struct f_val +#define FIA_VALP const struct f_val * +#define FIA_FRET enum filter_return +#define FIA_ECS enum ec_subtype +#define FIA_SA struct f_static_attr +#define FIA_EA struct f_dynamic_attr +#define FIA_RTC const struct rtable_config * +#define FIA_TREE const struct f_tree * +#define FIA_STRING const char * +#define F(c, ...) \ + struct f_inst *f_new_inst_##c(enum f_instruction_code MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))()(MACRO_FOREACH(FIA, __VA_ARGS__))); +FI__LIST +#undef F +#undef FIA_ARG +#undef FIA_LINE +#undef FIA_LINEP +#undef FIA_COUNT +#undef FIA_SYMBOL +#undef FIA_VALI +#undef FIA_VALP +#undef FIA_FRET +#undef FIA_ECS +#undef FIA_SA +#undef FIA_EA +#undef FIA_RTC +#undef FIA_STRING +#undef FIA + +#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) + +/* Flags for instructions */ +enum f_instruction_flags { + FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ +}; + /* Filter structures for execution */ struct f_line; @@ -242,6 +256,7 @@ struct f_line_item { const struct f_val *vp; const struct symbol *sym; }; + struct f_val val; const struct f_line *lines[2]; enum filter_return fret; struct f_static_attr sa; @@ -267,9 +282,9 @@ struct filter { }; /* Convert the f_inst infix tree to the f_line structures */ -struct f_line *f_postfixify_concat(struct f_inst *root, ...); -static inline struct f_line *f_postfixify(struct f_inst *root) -{ return f_postfixify_concat(root, NULL); } +struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint count); +static inline struct f_line *f_postfixify(const struct f_inst *root) +{ return f_postfixify_concat(&root, 1); } #define F_VAL_STACK_MAX 4096 @@ -295,12 +310,9 @@ struct f_exec_stack { enum f_exception emask; /* Exception mask */ } item[F_EXEC_STACK_MAX]; uint cnt; /* Current stack size; 0 for empty */ - }; -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); +struct filter *f_new_where(const struct f_inst *); static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .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) diff --git a/filter/interpret.m4 b/filter/interpret.m4 index 829b48f6..f449d580 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -45,17 +45,22 @@ m4_define(ARG_ANY, `') m4_define(SYMBOL, `const struct symbol *sym = what->sym') -m4_define(VALI, `res = *what->vp') -m4_define(VALP, `res = *what->vp') +m4_define(VALI, `res = what->val') +m4_define(VALP, `res = what->val') +m4_define(VAR, `res = *what->vp') m4_define(FRET, `enum filter_return fret = what->fret') m4_define(ECS, `enum ec_subtype ecs = what->ecs') m4_define(RTC, `struct rtable *table = what->rtc->table') m4_define(STATIC_ATTR, `struct f_static_attr sa = what->sa') m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da') +m4_define(TREE, `') +m4_define(STRING, `') +m4_define(COUNT, `') m4_define(POSTFIXIFY, `') m4_define(LINE_SIZE, `') m4_define(SAME, `') -m4_define(COUNT, `') +m4_define(STRUCT, `') +m4_define(NEW, `') m4_m4wrap(` m4_divert(0)DNL diff --git a/filter/line-size.m4 b/filter/line-size.m4 index 0c005fa1..2c6b500b 100644 --- a/filter/line-size.m4 +++ b/filter/line-size.m4 @@ -10,13 +10,16 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `m4_divert(1)break; case $1: cnt += 1; +m4_define(INST, `m4_divert(1) +#undef what +break; case $1: cnt += 1; +#define what ((const struct f_inst_$1 *) &(what_->i_$1)) m4_divert(-1)') -m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->f$1); m4_divert(-1)') -m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->f$1); m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p); +m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->f$1); m4_divert(-1)') m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)') @@ -24,7 +27,8 @@ m4_m4wrap(` m4_divert(0)DNL case FI_NOP: bug("This shall not happen"); m4_undivert(1) -break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +#undef what +break; default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); ') m4_changequote([[,]]) diff --git a/filter/new.m4 b/filter/new.m4 new file mode 100644 index 00000000..ebb367d0 --- /dev/null +++ b/filter/new.m4 @@ -0,0 +1,84 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Construction of per-instruction structures +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# +# +# Diversions: +# 1 for prepared output +# 2 for function arguments +# 3 for function body + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(FNSTOP, `m4_divert(-1)') +m4_define(FNOUT, `m4_divert(1)') +m4_define(FNARG, `m4_divert(2)') +m4_define(FNBODY, `m4_divert(3)') + +m4_define(INST, `m4_define([[INST_NAME]], [[$1]])FNOUT()DNL +m4_undivert(2)DNL +m4_undivert(3)DNL + return what; +} + +struct f_inst *f_new_inst_$1(enum f_instruction_code fi_code +FNBODY()) { + struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); + what->fi_code = fi_code; + what->lineno = ifs->lino; +FNSTOP()') + +m4_define(WHAT, `what->i_[[]]INST_NAME()') + +m4_define(FNMETAARG, `FNARG(), $1 $2 +FNBODY() WHAT().$2 = $2; +FNSTOP()') +m4_define(ARG, `FNMETAARG(const struct f_inst *, f$1)') +m4_define(ARG_ANY, `FNMETAARG(const struct f_inst *, f$1)') +m4_define(LINE, `FNMETAARG(const struct f_inst *, f$1)') +m4_define(SYMBOL, `FNMETAARG(const struct symbol *, sym)') +m4_define(VALI, `FNMETAARG(struct f_val, vali)') +m4_define(VALP, `FNMETAARG(const struct f_val *, valp)') +m4_define(VAR, `FNARG(), const struct symbol * sym +FNBODY() WHAT().valp = (WHAT().sym = sym)->def; +FNSTOP()') +m4_define(FRET, `FNMETAARG(enum filter_return, fret)') +m4_define(ECS, `FNMETAARG(enum ec_subtype, ecs)') +m4_define(RTC, `FNMETAARG(const struct rtable_config *, rtc)') +m4_define(STATIC_ATTR, `FNMETAARG(struct f_static_attr, sa)') +m4_define(DYNAMIC_ATTR, `FNMETAARG(struct f_dynamic_attr, da)') +m4_define(COUNT, `FNMETAARG(uint, count)') +m4_define(TREE, `FNMETAARG(const struct f_tree *, tree)') +m4_define(STRING, `FNMETAARG(const char *, s)') +m4_define(NEW, `FNARG()$1 +FNBODY()$2 +FNSTOP()') + +m4_m4wrap(` +FNOUT() +m4_undivert(2) +m4_undivert(3) + +m4_divert(0) +#include "nest/bird.h" +#include "conf/conf.h" +#include "filter/filter.h" +#include "filter/f-inst-struct.h" + +struct f_inst *f_new_inst_FI_NOP(enum f_instruction_code fi_code) { + struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); + what->fi_code = fi_code; + what->lineno = ifs->lino; + +m4_undivert(1) + + return what; +} +') + +m4_changequote([[,]]) diff --git a/filter/postfixify.m4 b/filter/postfixify.m4 index 8c96ba64..36cadfba 100644 --- a/filter/postfixify.m4 +++ b/filter/postfixify.m4 @@ -10,37 +10,45 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what->fi_code; -dest->items[pos].lineno = what->lineno;') +m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what_->fi_code; +dest->items[pos].lineno = what_->lineno;') m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER -break; case $1: +#undef what +break; case $1: +#define what ((const struct f_inst_$1 *) &(what_->i_$1)) m4_divert(-1)')) -m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos); +m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->f$1, pos); m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos); +m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->f$1, pos); m4_divert(-1)') -m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p); +m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->f$1); m4_divert(-1)') -m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p; +m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->fl$1; m4_divert(-1)') -m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p; +m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->sym; m4_divert(-1)') -m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val); +m4_define(VALI, `m4_divert(1)dest->items[pos].val = what->vali; m4_divert(-1)') -m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def; +m4_define(VALP, `m4_divert(1)dest->items[pos].val = *(what->valp); m4_divert(-1)') -m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i; +m4_define(VAR, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; m4_divert(-1)') -m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux; +m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->fret; m4_divert(-1)') -m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc; +m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->ecs; +m4_divert(-1)') +m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->rtc; m4_divert(-1)') m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa; m4_divert(-1)') m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da; m4_divert(-1)') -m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->a[$1-1].i; +m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->count; +m4_divert(-1)') +m4_define(TREE, `m4_divert(1)dest->items[pos].tree = what->tree; +m4_divert(-1)') +m4_define(STRING, `m4_divert(1)dest->items[pos].s = what->s; m4_divert(-1)') m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)') @@ -49,7 +57,8 @@ m4_divert(0)DNL case FI_NOP: bug("This shall not happen"); m4_undivert(1) POSTFIXIFY_TRAILER -break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +#undef what +break; default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); ') m4_changequote([[,]]) diff --git a/filter/same.m4 b/filter/same.m4 index 73f2d1c3..10979449 100644 --- a/filter/same.m4 +++ b/filter/same.m4 @@ -29,7 +29,9 @@ m4_divert(-1)') m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0; m4_divert(-1)') -m4_define(VALP, `') +m4_define(VALP, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0; +m4_divert(-1)') +m4_define(VAR, `SYMBOL()VALP()') m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0; m4_divert(-1)') diff --git a/filter/struct.m4 b/filter/struct.m4 new file mode 100644 index 00000000..66205bfd --- /dev/null +++ b/filter/struct.m4 @@ -0,0 +1,67 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Definition of per-instruction structures +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +m4_define(INST, `m4_divert(2)struct f_inst_$1 i_$1; +m4_divert(1)}; +struct f_inst_$1 { +m4_divert(-1)')) +m4_define(ARG, `m4_divert(1)const struct f_inst *f$1; +m4_divert(-1)') +m4_define(ARG_ANY, `m4_divert(1)const struct f_inst *f$1; +m4_divert(-1)') +m4_define(LINE, `m4_divert(1)const struct f_inst *f$1; +m4_divert(-1)') +m4_define(LINEP, `m4_divert(1)const struct f_line *fl$1; +m4_divert(-1)') +m4_define(SYMBOL, `m4_divert(1)const struct symbol *sym; +m4_divert(-1)') +m4_define(VALI, `m4_divert(1)struct f_val vali; +m4_divert(-1)') +m4_define(VALP, `m4_divert(1)const struct f_val *valp; +m4_divert(-1)') +m4_define(VAR, `VALP()SYMBOL()') +m4_define(FRET, `m4_divert(1)enum filter_return fret; +m4_divert(-1)') +m4_define(ECS, `m4_divert(1)enum ec_subtype ecs; +m4_divert(-1)') +m4_define(RTC, `m4_divert(1)const struct rtable_config *rtc; +m4_divert(-1)') +m4_define(STATIC_ATTR, `m4_divert(1)struct f_static_attr sa; +m4_divert(-1)') +m4_define(DYNAMIC_ATTR, `m4_divert(1)struct f_dynamic_attr da; +m4_divert(-1)') +m4_define(COUNT, `m4_divert(1)uint count; +m4_divert(-1)') +m4_define(TREE, `m4_divert(1)const struct f_tree *tree; +m4_divert(-1)') +m4_define(STRING, `m4_divert(1)const char *s; +m4_divert(-1)') +m4_define(STRUCT, `m4_divert(1)$1 +m4_divert(-1)') + +m4_m4wrap(` +m4_divert(0)DNL +struct f_inst_FI_NOP { +m4_undivert(1) +}; + +struct f_inst { + const struct f_inst *next; /* Next instruction */ + enum f_instruction_code fi_code; /* Instruction code */ + int lineno; /* Line number */ + union { + m4_undivert(2) + }; +}; +') + +m4_changequote([[,]]) diff --git a/nest/attrs.h b/nest/attrs.h index d9d97136..37227d9b 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -123,7 +123,7 @@ enum ec_subtype { EC_RT = 0x0002, EC_RO = 0x0003, EC_GENERIC = 0xFFFF, -} PACKED; +}; /* Transitive bit (for first u32 half of EC) */ #define EC_TBIT 0x40000000 diff --git a/proto/static/config.Y b/proto/static/config.Y index 56caef24..527046ee 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -14,7 +14,7 @@ CF_DEFINES #define STATIC_CFG ((struct static_config *) this_proto) static struct static_route *this_srt, *this_snh; -static struct f_inst *this_srt_cmds, **this_srt_last_cmd; +static struct f_inst *this_srt_cmds, *this_srt_last_cmd; static struct static_route * static_nexthop_new(void) @@ -111,7 +111,7 @@ stat_route0: ROUTE net_any { add_tail(&STATIC_CFG->routes, &this_srt->n); this_srt->net = $2; this_srt_cmds = NULL; - this_srt_last_cmd = &this_srt_cmds; + this_srt_last_cmd = NULL; this_srt->mp_next = NULL; this_snh = NULL; } @@ -137,7 +137,13 @@ stat_route: ; stat_route_item: - cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); } + cmd { + if (this_srt_last_cmd) + f_inst_next(this_srt_last_cmd, $1); + else + this_srt_cmds = $1; + this_srt_last_cmd = $1; + } ; stat_route_opts: From 713658798dfafabcd0a74f510c1639f6e3c9c820 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 23 Jan 2019 17:08:27 +0100 Subject: [PATCH 18/88] GDB pretty printers: f_inst and f_val. --- bird-gdb.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/birdlib.h | 9 ++++++ 2 files changed, 93 insertions(+) create mode 100644 bird-gdb.py diff --git a/bird-gdb.py b/bird-gdb.py new file mode 100644 index 00000000..e91a633f --- /dev/null +++ b/bird-gdb.py @@ -0,0 +1,84 @@ +class BIRDPrinter: + def __init__(self, val): + self.val = val + + @classmethod + def lookup(cls, val): + if val.type.code != cls.typeCode: + return None + if val.type.tag != cls.typeTag: + return None + + return cls(val) + + +class BIRDFValPrinter(BIRDPrinter): + "Print BIRD\s struct f_val" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_val" + + codemap = { + "T_INT": "i", + "T_BOOL": "i", + "T_PAIR": "i", + "T_QUAD": "i", + "T_ENUM_RTS": "i", + "T_ENUM_BGP_ORIGIN": "i", + "T_ENUM_SCOPE": "i", + "T_ENUM_RTC": "i", + "T_ENUM_RTD": "i", + "T_ENUM_ROA": "i", + "T_ENUM_NETTYPE": "i", + "T_ENUM_RA_PREFERENCE": "i", + "T_IP": "ip", + "T_NET": "net", + "T_STRING": "s", + "T_PATH_MASK": "path_mask", + "T_PATH": "ad", + "T_CLIST": "ad", + "T_EC": "ec", + "T_ECLIST": "ad", + "T_LC": "lc", + "T_LCLIST": "ad", + "T_RD": "ec", + "T_PATH_MASK_ITEM": "pmi", + "T_SET": "t", + "T_PREFIX_SET": "ti", + } + + def to_string(self): + code = self.val['type'] + if code.type.code != gdb.TYPE_CODE_ENUM or code.type.tag != "f_type": + raise Exception("Strange 'type' element in f_val") + + if str(code) == "T_VOID": + return "T_VOID" + else: + return "(%(c)s) %(v)s" % { "c": code, "v": self.val['val'][self.codemap[str(code)]] } + + def display_hint(self): + return "map" + +class BIRDFInstPrinter(BIRDPrinter): + "Print BIRD's struct f_inst" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_inst" + + def to_string(self): + code = self.val['fi_code'] + if str(code) == "FI_NOP": + return str(code) + ": " + str(self.val.cast(gdb.lookup_type("const char [%(siz)d]" % { "siz": self.val.type.sizeof }))) + return str(code) + ": " + str(self.val['i_' + str(code)]) + +# def children(self): # children iterator + def display_hint(self): + return "map" + + +def register_printers(objfile): + objfile.pretty_printers.append(BIRDFInstPrinter.lookup) + objfile.pretty_printers.append(BIRDFValPrinter.lookup) + +register_printers(gdb.current_objfile()) + +print("BIRD pretty printers loaded OK.") diff --git a/lib/birdlib.h b/lib/birdlib.h index 7cd78032..6fcc202f 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -164,6 +164,15 @@ void debug(const char *msg, ...); /* Printf to debug output */ #define ASSERT(x) do { if (!(x)) log(L_BUG "Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0) #endif +#ifdef DEBUGGING +asm( + ".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n" + ".byte 1\n" /* Python */ + ".asciz \"bird-gdb.py\"\n" + ".popsection\n" + ); +#endif + /* Pseudorandom numbers */ u32 random_u32(void); From c0e958e022aac79f69e6aca2652fdb6a529e68e2 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 30 Jan 2019 14:03:47 +0100 Subject: [PATCH 19/88] Filter + Config: Fix bugs, tests and split symbols by type --- conf/cf-lex.l | 22 +++++-- conf/conf.h | 4 -- conf/confbase.Y | 35 ++++++---- filter/config.Y | 144 +++++++++++++++++++++++------------------- filter/f-inst.c | 13 ++-- filter/filter.h | 22 ++++++- filter/filter_test.c | 35 ++++++---- filter/test.conf | 11 +++- nest/config.Y | 52 +++++++-------- proto/babel/config.Y | 8 +-- proto/bfd/config.Y | 4 +- proto/ospf/config.Y | 16 ++--- proto/ospf/ospf.c | 2 +- proto/ospf/ospf.h | 2 +- proto/rip/config.Y | 4 +- proto/static/config.Y | 2 +- 16 files changed, 224 insertions(+), 152 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9bbb3660..5e7c8418 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -285,7 +285,18 @@ else: { } cf_lval.s = cf_get_symbol(yytext); - return SYM; + switch (cf_lval.s->class) { + case SYM_VOID: return CF_SYM_VOID; + case SYM_PROTO: return CF_SYM_PROTO; + case SYM_TEMPLATE: return CF_SYM_TEMPLATE; + case SYM_FUNCTION: return CF_SYM_FUNCTION; + case SYM_FILTER: return CF_SYM_FILTER; + case SYM_TABLE: return CF_SYM_TABLE; + case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE; + case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE; + case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT; + default: bug("Unknown symbol class %d", cf_lval.s->class); + } } (.|\n) { @@ -723,9 +734,6 @@ cf_pop_scope(void) char * cf_symbol_class_name(struct symbol *sym) { - if (cf_symbol_is_constant(sym)) - return "constant"; - switch (sym->class) { case SYM_VOID: @@ -740,6 +748,12 @@ cf_symbol_class_name(struct symbol *sym) return "filter"; case SYM_TABLE: return "routing table"; + case SYM_ATTRIBUTE: + return "custom attribute"; + case SYM_CONSTANT_RANGE: + return "constant"; + case SYM_VARIABLE_RANGE: + return "variable"; default: return "unknown type"; } diff --git a/conf/conf.h b/conf/conf.h index 6138ccec..4e3addb3 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -165,10 +165,6 @@ void cf_push_scope(struct symbol *); void cf_pop_scope(void); char *cf_symbol_class_name(struct symbol *sym); -static inline int cf_symbol_is_constant(struct symbol *sym) -{ return (sym->class & 0xff00) == SYM_CONSTANT; } - - /* Parser */ extern char *cf_text; diff --git a/conf/confbase.Y b/conf/confbase.Y index 13f6aade..2195e8fc 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -55,6 +55,7 @@ CF_DECLS enum ec_subtype ecs; struct f_dynamic_attr fda; struct f_static_attr fsa; + struct f_lval flv; struct filter *f; struct f_tree *e; struct f_trie *trie; @@ -81,7 +82,7 @@ CF_DECLS %token IP4 %token IP6 %token VPN_RD -%token SYM +%token CF_SYM_VOID CF_SYM_PROTO CF_SYM_TEMPLATE CF_SYM_FUNCTION CF_SYM_FILTER CF_SYM_TABLE CF_SYM_ATTRIBUTE CF_SYM_VARIABLE CF_SYM_CONSTANT %token TEXT %type ipa_scope @@ -93,6 +94,7 @@ CF_DECLS %type label_stack_start label_stack %type text opttext +%type symbol %nonassoc PREFIX_DUMMY %left AND OR @@ -125,7 +127,7 @@ conf: ';' ; conf: definition ; definition: - DEFINE SYM '=' term ';' { + DEFINE CF_SYM_VOID '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); cf_define_symbol($2, SYM_CONSTANT | val->type, val); @@ -135,18 +137,29 @@ definition: expr: NUM | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } - | SYM { + | CF_SYM_CONSTANT { if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected"); $$ = SYM_VAL($1).i; } ; - expr_us: expr S { $$ = $1 S_; } | expr MS { $$ = $1 MS_; } | expr US { $$ = $1 US_; } ; +symbol: + CF_SYM_VOID + | CF_SYM_PROTO + | CF_SYM_TEMPLATE + | CF_SYM_FUNCTION + | CF_SYM_FILTER + | CF_SYM_TABLE + | CF_SYM_ATTRIBUTE + | CF_SYM_VARIABLE + | CF_SYM_CONSTANT + ; + /* Switches */ bool: @@ -164,7 +177,7 @@ bool: ipa: IP4 { $$ = ipa_from_ip4($1); } | IP6 { $$ = ipa_from_ip6($1); } - | SYM { + | CF_SYM_CONSTANT { if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected"); $$ = SYM_VAL($1).ip; } @@ -172,7 +185,7 @@ ipa: ipa_scope: /* empty */ { $$ = NULL; } - | '%' SYM { $$ = if_get_by_name($2->name); } + | '%' symbol { $$ = if_get_by_name($2->name); } ; @@ -279,7 +292,7 @@ net_: net_ip6: net_ip6_ - | SYM { + | CF_SYM_CONSTANT { if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6)) cf_error("IPv6 network expected"); $$ = * SYM_VAL($1).net; @@ -288,7 +301,7 @@ net_ip6: net_ip: net_ip_ - | SYM { + | CF_SYM_CONSTANT { if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net)) cf_error("IP network expected"); $$ = * SYM_VAL($1).net; @@ -297,7 +310,7 @@ net_ip: net_any: net_ - | SYM { + | CF_SYM_CONSTANT { if ($1->class != (SYM_CONSTANT | T_NET)) cf_error("Network expected"); $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */ @@ -309,7 +322,7 @@ net_or_ipa: | net_ip6_ | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); } | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); } - | SYM { + | CF_SYM_CONSTANT { if ($1->class == (SYM_CONSTANT | T_IP)) net_fill_ip_host(&($$), SYM_VAL($1).ip); else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net)) @@ -346,7 +359,7 @@ time: text: TEXT - | SYM { + | CF_SYM_CONSTANT { if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected"); $$ = SYM_VAL($1).s; } diff --git a/filter/config.Y b/filter/config.Y index 607f534e..1306849f 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -17,7 +17,7 @@ static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } #define f_generate_complex(fi_code, da, arg) \ - f_new_inst(FI_EA_SET, da, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg)) + f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) /* * Sets and their items are during parsing handled as lists, linked @@ -179,7 +179,7 @@ f_generate_empty(struct f_dynamic_attr dyn) cf_error("Can't empty that attribute"); } - return f_new_inst(FI_EA_SET, dyn, f_new_inst(FI_CONSTANT, empty)); + return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); } #if 0 @@ -389,6 +389,37 @@ assert_done(struct f_inst *expr, const char *start, const char *end) : "???"); } +static struct f_inst * +assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end) +{ + struct f_inst *setter, *getter, *checker; + switch (lval->type) { + case F_LVAL_VARIABLE: + setter = f_new_inst(FI_SET, expr, lval->sym); + getter = f_new_inst(FI_VARIABLE, lval->sym); + break; + case F_LVAL_PREFERENCE: + setter = f_new_inst(FI_PREF_SET, expr); + getter = f_new_inst(FI_PREF_GET); + break; + case F_LVAL_SA: + setter = f_new_inst(FI_RTA_SET, expr, lval->sa); + getter = f_new_inst(FI_RTA_GET, lval->sa); + break; + case F_LVAL_EA: + setter = f_new_inst(FI_EA_SET, expr, lval->da); + getter = f_new_inst(FI_EA_GET, lval->da); + break; + default: + bug("Unknown lval type"); + } + + checker = f_new_inst(FI_EQ, expr, getter); + f_inst_next(setter, checker); + + return assert_done(setter, start, end); +} + CF_DECLS CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, @@ -407,17 +438,18 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, - BT_ASSERT, BT_TEST_SUITE, FORMAT) + BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, FORMAT) %nonassoc THEN %nonassoc ELSE %type function_params declsn %type cmds_int function_body -%type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail one_decl decls +%type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls %type dynamic_attr %type static_attr %type filter filter_body where_filter +%type lvalue %type type %type ec_kind %type break_command @@ -432,7 +464,7 @@ CF_GRAMMAR conf: filter_def ; filter_def: - FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } + FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } filter_body { $2->def = $4; $4->name = $2->name; @@ -447,16 +479,13 @@ filter_eval: ; conf: custom_attr ; -custom_attr: ATTRIBUTE type SYM ';' { +custom_attr: ATTRIBUTE type CF_SYM_VOID ';' { cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda); }; conf: bt_test_suite ; bt_test_suite: - BT_TEST_SUITE '(' SYM ',' text ')' { - if (!($3->class & SYM_FUNCTION)) - cf_error("Function expected"); - + BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' { struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite)); t->fn = $3->def; t->fn_name = $3->name; @@ -505,7 +534,7 @@ type: ; one_decl: - type SYM { + type CF_SYM_VOID { struct f_val * val = cfg_alloc(sizeof(struct f_val)); val->type = T_VOID; $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); @@ -545,8 +574,7 @@ filter_body: ; filter: - SYM { - if ($1->class != SYM_FILTER) cf_error("No such filter."); + CF_SYM_FILTER { $$ = $1->def; } | filter_body @@ -573,7 +601,7 @@ function_body: conf: function_def ; function_def: - FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); + FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); cf_push_scope($2); } function_params function_body { @@ -647,8 +675,7 @@ set_atom: if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } - | SYM { - if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name); + | CF_SYM_CONSTANT { if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); $$ = *(struct f_val *)($1->def); } @@ -764,7 +791,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } ; bgp_path_expr: - symbol { $$ = $1; } + symbol_value { $$ = $1; } | '(' term ')' { $$ = $2; } ; @@ -806,31 +833,17 @@ constructor: ; -rtadot: /* EMPTY, we are not permitted RTA. prefix */ - ; - function_call: - SYM '(' var_list ')' { + CF_SYM_FUNCTION '(' var_list ')' { $$ = f_new_inst(FI_CALL, $1, $3); } ; -symbol: - SYM { - switch ($1->class & 0xffff) { - case SYM_CONSTANT_RANGE: - $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); - break; - case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VARIABLE, $1); - break; - case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); - break; - default: - cf_error("%s: variable expected.", $1->name); - } - } +symbol_value: + CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); } + | CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); } + | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); } + ; static_attr: FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); } @@ -863,15 +876,15 @@ term: | '!' term { $$ = f_new_inst(FI_NOT, $2); } | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); } - | symbol { $$ = $1; } + | symbol_value { $$ = $1; } | constant { $$ = $1; } | constructor { $$ = $1; } | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); } - | rtadot static_attr { $$ = f_new_inst(FI_RTA_GET, $2); } + | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } - | rtadot dynamic_attr { $$ = f_new_inst(FI_EA_GET, $2); } + | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); } | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); } @@ -888,10 +901,10 @@ term: /* Communities */ /* This causes one shift/reduce conflict - | rtadot dynamic_attr '.' ADD '(' term ')' { } - | rtadot dynamic_attr '.' DELETE '(' term ')' { } - | rtadot dynamic_attr '.' CONTAINS '(' term ')' { } - | rtadot dynamic_attr '.' RESET{ } + | dynamic_attr '.' ADD '(' term ')' { } + | dynamic_attr '.' DELETE '(' term ')' { } + | dynamic_attr '.' CONTAINS '(' term ')' { } + | dynamic_attr '.' RESET{ } */ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); } @@ -956,32 +969,29 @@ cmd: | IF term THEN block ELSE block { $$ = f_new_inst(FI_CONDITION, $2, $4, $6); } - | SYM '=' term ';' { - DBG( "Ook, we'll set value\n" ); - if ($1->class == SYM_ATTRIBUTE) { - $$ = f_new_inst(FI_EA_SET, *((struct f_dynamic_attr *) $1->def), $3); - } else if (($1->class & ~T_MASK) == SYM_VARIABLE) { - $$ = f_new_inst(FI_SET, $3, $1); - } else - cf_error( "Symbol `%s' is read-only.", $1->name ); + | CF_SYM_ATTRIBUTE '=' term ';' { + $$ = f_new_inst(FI_EA_SET, $3, *((struct f_dynamic_attr *) $1->def)); + } + | CF_SYM_VARIABLE '=' term ';' { + $$ = f_new_inst(FI_SET, $3, $1); } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); $$ = f_new_inst(FI_RETURN, $2); } - | rtadot dynamic_attr '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $2, $4); + | dynamic_attr '=' term ';' { + $$ = f_new_inst(FI_EA_SET, $3, $1); } - | rtadot static_attr '=' term ';' { - if ($2.readonly) + | static_attr '=' term ';' { + if ($1.readonly) cf_error( "This static attribute is read-only."); - $$ = f_new_inst(FI_RTA_SET, $2, $4); + $$ = f_new_inst(FI_RTA_SET, $3, $1); } | PREFERENCE '=' term ';' { $$ = f_new_inst(FI_PREF_SET, $3); } - | UNSET '(' rtadot dynamic_attr ')' ';' { - $$ = f_new_inst(FI_EA_UNSET, $4); + | UNSET '(' dynamic_attr ')' ';' { + $$ = f_new_inst(FI_EA_UNSET, $3); } | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } @@ -989,12 +999,13 @@ cmd: $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); } - | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } - | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); } - | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); } - | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); } - | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); } + | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); } + | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); } + | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); } + | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); } + | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } + | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); } ; get_cf_position: @@ -1002,5 +1013,10 @@ get_cf_position: $$ = cf_text; }; +lvalue: + CF_SYM_VARIABLE { $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } + | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; } + | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } + | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; CF_END diff --git a/filter/f-inst.c b/filter/f-inst.c index ae2b5289..0dd9f9f6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -109,7 +109,7 @@ ARG_ANY(1); COUNT(2); - NEW([[]], [[ + NEW(, [[ uint len = 0; uint dyn = 0; for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) @@ -329,9 +329,9 @@ } INST(FI_RTA_SET, 1, 0) { - STATIC_ATTR; ACCESS_RTE; ARG_ANY(1); + STATIC_ATTR; if (sa.f_type != v1.type) runtime( "Attempt to set static attribute to incompatible type" ); @@ -475,10 +475,10 @@ } INST(FI_EA_SET, 1, 0) { - DYNAMIC_ATTR; ACCESS_RTE; ACCESS_EATTRS; ARG_ANY(1); + DYNAMIC_ATTR; { struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); @@ -719,7 +719,7 @@ /* Then push the arguments */ LINE(1,1); - NEW([[]], [[ + NEW(, [[ if (sym->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); @@ -984,5 +984,8 @@ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ ARG(1, T_BOOL); STRING; - CALL(bt_assert_hook, res.val.i, what); + if (!bt_assert_hook) + runtime("No bt_assert hook registered, can't assert"); + + bt_assert_hook(res.val.i, what); } diff --git a/filter/filter.h b/filter/filter.h index 39f16e93..15a24fd4 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -128,6 +128,24 @@ enum filter_return { F_QUITBIRD, }; +/* Filter l-value type */ +enum f_lval_type { + F_LVAL_VARIABLE, + F_LVAL_PREFERENCE, + F_LVAL_SA, + F_LVAL_EA, +}; + +/* Filter l-value */ +struct f_lval { + enum f_lval_type type; + union { + const struct symbol *sym; + struct f_dynamic_attr da; + struct f_static_attr sa; + }; +}; + /* Filter instruction declarations */ #define FI__LIST \ F(FI_NOP) \ @@ -159,9 +177,9 @@ enum filter_return { F(FI_CONDITION, ARG, LINE, LINE) \ F(FI_PRINT_AND_DIE, ARG, FRET) \ F(FI_RTA_GET, SA) \ - F(FI_RTA_SET, SA, ARG) \ + F(FI_RTA_SET, ARG, SA) \ F(FI_EA_GET, EA) \ - F(FI_EA_SET, EA, ARG) \ + F(FI_EA_SET, ARG, EA) \ F(FI_EA_UNSET, EA) \ F(FI_PREF_GET) \ F(FI_PREF_SET, ARG) \ diff --git a/filter/filter_test.c b/filter/filter_test.c index e19b0a75..af6b590f 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -22,19 +22,21 @@ #define BT_CONFIG_FILE "filter/test.conf" -static struct config * -parse_config_file(const void *filename_void) +struct parse_config_file_arg { + struct config **cp; + const char *filename; +}; + +static int +parse_config_file(const void *argv) { - bt_bird_init(); - - size_t fn_size = strlen((const char *) filename_void) + 1; + const struct parse_config_file_arg *arg = argv; + size_t fn_size = strlen(arg->filename) + 1; char *filename = alloca(fn_size); - strncpy(filename, filename_void, fn_size); - - struct config *c = bt_config_file_parse(filename); - bt_bird_cleanup(); - - return c; + strncpy(filename, arg->filename, fn_size); + + *(arg->cp) = bt_config_file_parse(filename); + return !!*(arg->cp); } static int @@ -68,13 +70,18 @@ int main(int argc, char *argv[]) { bt_init(argc, argv); + bt_bird_init(); + + bt_assert_hook = bt_assert_filter; - struct config *c = parse_config_file(BT_CONFIG_FILE); + struct config *c = NULL; + struct parse_config_file_arg pcfa = { .cp = &c, .filename = BT_CONFIG_FILE }; + bt_test_suite_base(parse_config_file, "conf", (const void *) &pcfa, 0, 0, "parse config file"); + + bt_bird_cleanup(); if (c) { - bt_assert_hook = bt_assert_filter; - struct f_bt_test_suite *t; WALK_LIST(t, c->tests) bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc); diff --git a/filter/test.conf b/filter/test.conf index 39b349cc..e6b6ca4e 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -1336,7 +1336,7 @@ bt_test_suite(t_mixed_prefix, "Testing mixed net types"); filter vpn_filter { - bt_assert(format(net) = "0:1:2 10.1.10.0/24"); + bt_assert(format(net) = "1:2 10.1.10.0/24"); bt_assert(net.type = NET_VPN4); bt_assert(net.type != NET_IP4); bt_assert(net.type != NET_IP6); @@ -1347,6 +1347,15 @@ filter vpn_filter NET_IP6: print "IPV6"; } +# aoiufahkejtrhaweifdsbhydkfj,ysdnm + + bt_check_assign(from, 10.20.30.40); + bt_check_assign(gw, 55.55.55.44); + + bgp_community.add((3,5)); + bgp_ext_community.add((ro, 135, 999)); + bgp_large_community.add((6464156, 89646354, 8675643)); + accept; } diff --git a/nest/config.Y b/nest/config.Y index 51fb0bd7..fb75c593 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -88,7 +88,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID) %type idval %type imexport %type rtable -%type optsym +%type optproto sym_proto_or_template %type r_args %type sym_args %type proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm @@ -114,7 +114,7 @@ idval: NUM { $$ = $1; } | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } | IP4 { $$ = ip4_to_u32($1); } - | SYM { + | CF_SYM_CONSTANT { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) $$ = SYM_VAL($1).i; else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip)) @@ -156,7 +156,7 @@ table_sorted: | SORTED { $$ = 1; } ; -table: net_type TABLE SYM table_sorted { +table: net_type TABLE CF_SYM_VOID table_sorted { struct rtable_config *cf; cf = rt_new_table($3, $1); cf->sorted = $4; @@ -173,6 +173,8 @@ proto_start: | TEMPLATE { $$ = SYM_TEMPLATE; } ; +sym_proto_or_template: CF_SYM_PROTO | CF_SYM_TEMPLATE ; + proto_name: /* EMPTY */ { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); @@ -180,11 +182,11 @@ proto_name: s->def = this_proto; this_proto->name = s->name; } - | SYM { + | CF_SYM_VOID { cf_define_symbol($1, this_proto->class, this_proto); this_proto->name = $1->name; } - | FROM SYM { + | FROM sym_proto_or_template { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); s->class = this_proto->class; s->def = this_proto; @@ -193,7 +195,7 @@ proto_name: if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); proto_copy_config(this_proto, $2->def); } - | SYM FROM SYM { + | CF_SYM_VOID FROM sym_proto_or_template { cf_define_symbol($1, this_proto->class, this_proto); this_proto->name = $1->name; @@ -254,12 +256,7 @@ channel_end: proto_channel: channel_start channel_opt_list channel_end; -rtable: - SYM { - if ($1->class != SYM_TABLE) cf_error("Table expected"); - $$ = $1->def; - } - ; +rtable: CF_SYM_TABLE { $$ = $1->def; } ; imexport: FILTER filter { $$ = $2; } @@ -512,8 +509,8 @@ CF_CLI(SHOW PROTOCOLS, proto_patt2, [ | \"\"], [[Show routing CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show routing protocol details]]) { proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; -optsym: - SYM +optproto: + CF_SYM_PROTO | /* empty */ { $$ = NULL; } ; @@ -545,9 +542,8 @@ r_args: $$->show_for = 1; $$->addr = $3; } - | r_args TABLE SYM { + | r_args TABLE CF_SYM_TABLE { $$ = $1; - if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name); rt_show_add_table($$, ((struct rtable_config *)$3->def)->table); $$->tables_defined_by = RSD_TDB_DIRECT; } @@ -558,10 +554,10 @@ r_args: rt_show_add_table($$, t->table); $$->tables_defined_by = RSD_TDB_ALL; } - | r_args IMPORT TABLE SYM '.' r_args_channel { + | r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel { $$ = $1; struct proto_config *cf = (void *) $4->def; - if ($4->class != SYM_PROTO || !cf->proto) cf_error("%s is not a protocol", $4->name); + if (!cf->proto) cf_error("%s is not a protocol", $4->name); struct channel *c = proto_find_channel_by_name(cf->proto, $6); if (!c) cf_error("Channel %s.%s not found", $4->name, $6); if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6); @@ -590,30 +586,30 @@ r_args: $$ = $1; $$->filtered = 1; } - | r_args export_mode SYM { + | r_args export_mode CF_SYM_PROTO { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if (!c->proto) cf_error("%s is not a protocol", $3->name); $$->export_mode = $2; $$->export_protocol = c->proto; $$->tables_defined_by = RSD_TDB_INDIRECT; } - | r_args export_mode SYM '.' r_args_channel { + | r_args export_mode CF_SYM_PROTO '.' r_args_channel { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if (!c->proto) cf_error("%s is not a protocol", $3->name); $$->export_mode = $2; $$->export_channel = proto_find_channel_by_name(c->proto, $5); if (!$$->export_channel) cf_error("Export channel not found"); $$->tables_defined_by = RSD_TDB_INDIRECT; } - | r_args PROTOCOL SYM { + | r_args PROTOCOL CF_SYM_PROTO { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; if ($$->show_protocol) cf_error("Protocol specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if (!c->proto) cf_error("%s is not a protocol", $3->name); $$->show_protocol = c->proto; $$->tables_defined_by = RSD_TDB_INDIRECT; } @@ -647,7 +643,7 @@ r_args_for: $$ = cfg_alloc(sizeof(net_addr_ip6_sadr)); net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH); } - | SYM { + | CF_SYM_CONSTANT { if ($1->class == (SYM_CONSTANT | T_IP)) { $$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6)); @@ -709,7 +705,7 @@ sym_args: | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; } | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; } | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; } - | sym_args SYM { $$ = $1; $$->sym = $2; } + | sym_args symbol { $$ = $1; $$->sym = $2; } ; @@ -779,13 +775,13 @@ CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]]) { this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; proto_patt: - SYM { $$.ptr = $1; $$.patt = 0; } + CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; } | ALL { $$.ptr = NULL; $$.patt = 1; } | TEXT { $$.ptr = $1; $$.patt = 1; } ; proto_patt2: - SYM { $$.ptr = $1; $$.patt = 0; } + CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; } | { $$.ptr = NULL; $$.patt = 1; } | TEXT { $$.ptr = $1; $$.patt = 1; } ; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index b93a423b..78175323 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -129,16 +129,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_ CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); -CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [] [\"\"], [[Show information about Babel interfaces]]) +CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [] [\"\"], [[Show information about Babel interfaces]]) { babel_show_interfaces(proto_get_named($4, &proto_babel), $5); }; -CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about Babel neighbors]]) +CF_CLI(SHOW BABEL NEIGHBORS, optproto opttext, [] [\"\"], [[Show information about Babel neighbors]]) { babel_show_neighbors(proto_get_named($4, &proto_babel), $5); }; -CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [], [[Show information about Babel prefix entries]]) +CF_CLI(SHOW BABEL ENTRIES, optproto opttext, [], [[Show information about Babel prefix entries]]) { babel_show_entries(proto_get_named($4, &proto_babel)); }; -CF_CLI(SHOW BABEL ROUTES, optsym opttext, [], [[Show information about Babel route entries]]) +CF_CLI(SHOW BABEL ROUTES, optproto opttext, [], [[Show information about Babel route entries]]) { babel_show_routes(proto_get_named($4, &proto_babel)); }; CF_CODE diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 3f5714fd..41228e51 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -134,7 +134,7 @@ bfd_multihop: bfd_neigh_iface: /* empty */ { $$ = NULL; } - | '%' SYM { $$ = if_get_by_name($2->name); } + | '%' symbol { $$ = if_get_by_name($2->name); } | DEV text { $$ = if_get_by_name($2); } ; @@ -167,7 +167,7 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]); -CF_CLI(SHOW BFD SESSIONS, optsym, [], [[Show information about BFD sessions]]) +CF_CLI(SHOW BFD SESSIONS, optproto, [], [[Show information about BFD sessions]]) { bfd_show_sessions(proto_get_named($4, &proto_bfd)); }; CF_CODE diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 9669b708..38b09deb 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -504,29 +504,29 @@ dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ; CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); -CF_CLI(SHOW OSPF, optsym, [], [[Show information about OSPF protocol]]) +CF_CLI(SHOW OSPF, optproto, [], [[Show information about OSPF protocol]]) { ospf_sh(proto_get_named($3, &proto_ospf)); }; -CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about OSPF neighbors]]) +CF_CLI(SHOW OSPF NEIGHBORS, optproto opttext, [] [\"\"], [[Show information about OSPF neighbors]]) { ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); }; -CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [] [\"\"], [[Show information about interface]]) +CF_CLI(SHOW OSPF INTERFACE, optproto opttext, [] [\"\"], [[Show information about interface]]) { ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); }; CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [], [[Show information about OSPF network topology]]) -CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [], [[Show information about reachable OSPF network topology]]) +CF_CLI(SHOW OSPF TOPOLOGY, optproto opttext, [], [[Show information about reachable OSPF network topology]]) { ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); }; -CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [], [[Show information about all OSPF network topology]]) +CF_CLI(SHOW OSPF TOPOLOGY ALL, optproto opttext, [], [[Show information about all OSPF network topology]]) { ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); }; CF_CLI_HELP(SHOW OSPF STATE, [all] [], [[Show information about OSPF network state]]) -CF_CLI(SHOW OSPF STATE, optsym opttext, [], [[Show information about reachable OSPF network state]]) +CF_CLI(SHOW OSPF STATE, optproto opttext, [], [[Show information about reachable OSPF network state]]) { ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); }; -CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [], [[Show information about all OSPF network state]]) +CF_CLI(SHOW OSPF STATE ALL, optproto opttext, [], [[Show information about all OSPF network state]]) { ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); }; CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]); @@ -544,7 +544,7 @@ lsadb_args: | lsadb_args LSID idval { $$ = $1; $$->lsid = $3; } | lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; } | lsadb_args ROUTER idval { $$ = $1; $$->router = $3; } - | lsadb_args SYM { $$ = $1; $$->name = $2; } + | lsadb_args CF_SYM_PROTO { $$ = $1; $$->proto = (struct ospf_proto *) proto_get_named($2, &proto_ospf); } ; CF_CODE diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index ef2a0df4..816f33aa 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1402,7 +1402,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2) void ospf_sh_lsadb(struct lsadb_show_data *ld) { - struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf); + struct ospf_proto *p = ld->proto; uint num = p->gr->hash_entries; uint i, j; int last_dscope = -1; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 7fac47c8..82ae4df4 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -900,7 +900,7 @@ struct ospf_lsreq_header #define SH_ROUTER_SELF 0xffffffff struct lsadb_show_data { - struct symbol *name; /* Protocol to request data from */ + struct ospf_proto *proto; /* Protocol to request data from */ u16 type; /* LSA Type, 0 -> all */ u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */ u32 area; /* Specified for area scope */ diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 265912b2..4ab793d1 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -191,10 +191,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_T CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); -CF_CLI(SHOW RIP INTERFACES, optsym opttext, [] [\"\"], [[Show information about RIP interfaces]]) +CF_CLI(SHOW RIP INTERFACES, optproto opttext, [] [\"\"], [[Show information about RIP interfaces]]) { rip_show_interfaces(proto_get_named($4, &proto_rip), $5); }; -CF_CLI(SHOW RIP NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about RIP neighbors]]) +CF_CLI(SHOW RIP NEIGHBORS, optproto opttext, [] [\"\"], [[Show information about RIP neighbors]]) { rip_show_neighbors(proto_get_named($4, &proto_rip), $5); }; diff --git a/proto/static/config.Y b/proto/static/config.Y index 527046ee..0e53c978 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -157,7 +157,7 @@ stat_route_opt_list: ; -CF_CLI(SHOW STATIC, optsym, [], [[Show details of static protocol]]) +CF_CLI(SHOW STATIC, optproto, [], [[Show details of static protocol]]) { static_show(proto_get_named($3, &proto_static)); } ; CF_CODE From c1e97169cd96ce39337e75cfdf6882b180341f09 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 6 Feb 2019 14:41:39 +0100 Subject: [PATCH 20/88] Filter: M4 convertors polished a bit. --- filter/dump.m4 | 36 +++++++++++++++----------- filter/filter.c | 6 ++--- filter/interpret.m4 | 19 ++++++++------ filter/line-size.m4 | 29 +++++++++++++-------- filter/new.m4 | 36 +++++++++++--------------- filter/postfixify.m4 | 60 +++++++++++++++++++++++--------------------- filter/same.m4 | 35 +++++++++++++++----------- filter/struct.m4 | 52 +++++++++++++++++++++----------------- 8 files changed, 150 insertions(+), 123 deletions(-) diff --git a/filter/dump.m4 b/filter/dump.m4 index cb8e5c5f..4ea3e3be 100644 --- a/filter/dump.m4 +++ b/filter/dump.m4 @@ -10,34 +10,42 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `m4_divert(1)break; case $1: -m4_divert(-1)')) -m4_define(LINE, `m4_divert(1)f_dump_line(item->lines[$2], indent + 1); +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +case INST_NAME(): +m4_undivert(2) +break; +m4_divert(-1) +]])') +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') + +m4_define(LINE, `m4_divert(2)f_dump_line(item->lines[$2], indent + 1); m4_divert(-1)') m4_define(LINEP, `LINE($@)') -m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name); +m4_define(SYMBOL, `m4_divert(2)debug("%ssymbol %s\n", INDENT, item->sym->name); m4_divert(-1)') -m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(&item->val)); +m4_define(VALI, `m4_divert(2)debug("%svalue %s\n", INDENT, val_dump(&item->val)); m4_divert(-1)') -m4_define(VAR, `m4_divert(1)debug("%svar %s: value %s\n", INDENT, item->sym->name, val_dump(item->vp)); +m4_define(VAR, `m4_divert(2)debug("%svar %s: value %s\n", INDENT, item->sym->name, val_dump(item->vp)); m4_divert(-1)') -m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret); +m4_define(FRET, `m4_divert(2)debug("%sfilter return value %d\n", INDENT, item->fret); m4_divert(-1)') -m4_define(ECS, `m4_divert(1)debug("%sec subtype %d\n", INDENT, item->ecs); +m4_define(ECS, `m4_divert(2)debug("%sec subtype %d\n", INDENT, item->ecs); m4_divert(-1)') -m4_define(RTC, `m4_divert(1)debug("%sroute table %s\n", INDENT, item->rtc->name); +m4_define(RTC, `m4_divert(2)debug("%sroute table %s\n", INDENT, item->rtc->name); m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(1)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly); +m4_define(STATIC_ATTR, `m4_divert(2)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly); m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(1)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code); +m4_define(DYNAMIC_ATTR, `m4_divert(2)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code); m4_divert(-1)') -m4_define(DUMP, `m4_divert(1)$1m4_divert(-1)') +m4_define(DUMP, `m4_divert(2)$1m4_divert(-1)') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -case FI_NOP: bug("This shall not happen"); m4_undivert(1) -break; default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff); + +default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff); ') m4_changequote([[,]]) diff --git a/filter/filter.c b/filter/filter.c index a69d1b3d..bb5e4235 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -626,7 +626,6 @@ inst_line_size(const struct f_inst *what_) return cnt; } -#if DEBUGGING #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) static const char f_dump_line_indent_str[] = " "; @@ -667,9 +666,6 @@ f_dump_line(const struct f_line *dest, int indent) debug("%sFilter line %p dump done\n", INDENT, dest); #undef INDENT } -#else -#define f_dump_line(...) -#endif static uint postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) @@ -695,7 +691,9 @@ f_postfixify_concat(const struct f_inst * const inst[], uint count) for (uint i=0; ilen = postfixify(out, inst[i], out->len); +#if DEBUGGING f_dump_line(out, 0); +#endif return out; } diff --git a/filter/interpret.m4 b/filter/interpret.m4 index f449d580..dfd5c6a7 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -10,10 +10,16 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `break; case $1: -m4_ifelse(eval($2 > 0), `if (vstk.cnt < $2) runtime("Stack underflow");', `') -vstk.cnt -= $2; -') +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +case INST_NAME(): +m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]]) +m4_undivert(2) +break; +m4_divert(-1) +]])') + +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])m4_define([[INST_INVAL]], [[$2]])m4_divert(2)') m4_define(ARG, `if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)') @@ -63,12 +69,11 @@ m4_define(STRUCT, `') m4_define(NEW, `') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -case FI_NOP: bug("This shall not happen"); m4_undivert(1) -break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); +default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); ') -m4_divert(1) m4_changequote([[,]]) diff --git a/filter/line-size.m4 b/filter/line-size.m4 index 2c6b500b..051d3b90 100644 --- a/filter/line-size.m4 +++ b/filter/line-size.m4 @@ -10,25 +10,32 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `m4_divert(1) +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +case INST_NAME(): +cnt += 1; +#define what ((const struct f_inst_]]INST_NAME()[[ *) &(what_->i_]]INST_NAME()[[)) +m4_undivert(2) #undef what -break; case $1: cnt += 1; -#define what ((const struct f_inst_$1 *) &(what_->i_$1)) +break; +m4_divert(-1) +]])') +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') + +m4_define(ARG, `m4_divert(2)cnt += inst_line_size(what->f$1); m4_divert(-1)') -m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->f$1); +m4_define(ARG_T, `m4_divert(2)cnt += inst_line_size(what->f$1); m4_divert(-1)') -m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->f$1); +m4_define(ARG_ANY, `m4_divert(2)cnt += inst_line_size(what->f$1); m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->f$1); -m4_divert(-1)') -m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)') +m4_define(LINE_SIZE, `m4_divert(2)$1m4_divert(-1)') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -case FI_NOP: bug("This shall not happen"); m4_undivert(1) -#undef what -break; default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); + +default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); ') m4_changequote([[,]]) diff --git a/filter/new.m4 b/filter/new.m4 index ebb367d0..d499c94b 100644 --- a/filter/new.m4 +++ b/filter/new.m4 @@ -20,23 +20,27 @@ m4_define(FNOUT, `m4_divert(1)') m4_define(FNARG, `m4_divert(2)') m4_define(FNBODY, `m4_divert(3)') -m4_define(INST, `m4_define([[INST_NAME]], [[$1]])FNOUT()DNL -m4_undivert(2)DNL -m4_undivert(3)DNL - return what; -} - -struct f_inst *f_new_inst_$1(enum f_instruction_code fi_code -FNBODY()) { +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +FNOUT()DNL +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +m4_undivert(2) +) { struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); what->fi_code = fi_code; what->lineno = ifs->lino; -FNSTOP()') +m4_undivert(3) + return what; +} +FNSTOP() +]]DNL +)') + +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') m4_define(WHAT, `what->i_[[]]INST_NAME()') m4_define(FNMETAARG, `FNARG(), $1 $2 -FNBODY() WHAT().$2 = $2; +FNBODY() WHAT().$2 = $2; FNSTOP()') m4_define(ARG, `FNMETAARG(const struct f_inst *, f$1)') m4_define(ARG_ANY, `FNMETAARG(const struct f_inst *, f$1)') @@ -60,25 +64,15 @@ FNBODY()$2 FNSTOP()') m4_m4wrap(` -FNOUT() -m4_undivert(2) -m4_undivert(3) - +INST_FLUSH() m4_divert(0) #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" #include "filter/f-inst-struct.h" -struct f_inst *f_new_inst_FI_NOP(enum f_instruction_code fi_code) { - struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); - what->fi_code = fi_code; - what->lineno = ifs->lino; - m4_undivert(1) - return what; -} ') m4_changequote([[,]]) diff --git a/filter/postfixify.m4 b/filter/postfixify.m4 index 36cadfba..853c9a51 100644 --- a/filter/postfixify.m4 +++ b/filter/postfixify.m4 @@ -10,55 +10,59 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what_->fi_code; -dest->items[pos].lineno = what_->lineno;') - -m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +case INST_NAME(): +#define what ((const struct f_inst_]]INST_NAME()[[ *) &(what_->i_]]INST_NAME()[[)) +m4_undivert(2) #undef what -break; case $1: -#define what ((const struct f_inst_$1 *) &(what_->i_$1)) -m4_divert(-1)')) -m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->f$1, pos); +dest->items[pos].fi_code = what_->fi_code; +dest->items[pos].lineno = what_->lineno; +break; +m4_divert(-1) +]])') +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') + +m4_define(ARG, `m4_divert(2)pos = postfixify(dest, what->f$1, pos); m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->f$1, pos); +m4_define(ARG_ANY, `m4_divert(2)pos = postfixify(dest, what->f$1, pos); m4_divert(-1)') -m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->f$1); +m4_define(LINE, `m4_divert(2)dest->items[pos].lines[$2] = f_postfixify(what->f$1); m4_divert(-1)') -m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->fl$1; +m4_define(LINEP, `m4_divert(2)dest->items[pos].lines[$2] = what->fl$1; m4_divert(-1)') -m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->sym; +m4_define(SYMBOL, `m4_divert(2)dest->items[pos].sym = what->sym; m4_divert(-1)') -m4_define(VALI, `m4_divert(1)dest->items[pos].val = what->vali; +m4_define(VALI, `m4_divert(2)dest->items[pos].val = what->vali; m4_divert(-1)') -m4_define(VALP, `m4_divert(1)dest->items[pos].val = *(what->valp); +m4_define(VALP, `m4_divert(2)dest->items[pos].val = *(what->valp); m4_divert(-1)') -m4_define(VAR, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; +m4_define(VAR, `m4_divert(2)dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; m4_divert(-1)') -m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->fret; +m4_define(FRET, `m4_divert(2)dest->items[pos].fret = what->fret; m4_divert(-1)') -m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->ecs; +m4_define(ECS, `m4_divert(2)dest->items[pos].ecs = what->ecs; m4_divert(-1)') -m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->rtc; +m4_define(RTC, `m4_divert(2)dest->items[pos].rtc = what->rtc; m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa; +m4_define(STATIC_ATTR, `m4_divert(2)dest->items[pos].sa = what->sa; m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da; +m4_define(DYNAMIC_ATTR, `m4_divert(2)dest->items[pos].da = what->da; m4_divert(-1)') -m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->count; +m4_define(COUNT, `m4_divert(2)dest->items[pos].count = what->count; m4_divert(-1)') -m4_define(TREE, `m4_divert(1)dest->items[pos].tree = what->tree; +m4_define(TREE, `m4_divert(2)dest->items[pos].tree = what->tree; m4_divert(-1)') -m4_define(STRING, `m4_divert(1)dest->items[pos].s = what->s; +m4_define(STRING, `m4_divert(2)dest->items[pos].s = what->s; m4_divert(-1)') -m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)') +m4_define(POSTFIXIFY, `m4_divert(2)$1m4_divert(-1)') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -case FI_NOP: bug("This shall not happen"); m4_undivert(1) -POSTFIXIFY_TRAILER -#undef what -break; default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); + +default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); ') m4_changequote([[,]]) diff --git a/filter/same.m4 b/filter/same.m4 index 10979449..cf739af4 100644 --- a/filter/same.m4 +++ b/filter/same.m4 @@ -10,49 +10,54 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `m4_divert(1)break; case $1: -m4_divert(-1)') +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +case INST_NAME(): +m4_undivert(2) +break; +m4_divert(-1) +]])') +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') m4_define(ARG, `') m4_define(ARG_ANY, `') -m4_define(LINE, `m4_divert(1)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; +m4_define(LINE, `m4_divert(2)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; m4_divert(-1)') m4_define(LINEP, LINE) -m4_define(SYMBOL, `m4_divert(1){ +m4_define(SYMBOL, `m4_divert(2){ const struct symbol *s1 = f1->sym, *s2 = f2->sym; if (strcmp(s1->name, s2->name)) return 0; if (s1->class != s2->class) return 0; } m4_divert(-1)') -m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0; +m4_define(VALI, `m4_divert(2)if (!val_same(f1->vp, f2->vp)) return 0; m4_divert(-1)') -m4_define(VALP, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0; +m4_define(VALP, `m4_divert(2)if (!val_same(f1->vp, f2->vp)) return 0; m4_divert(-1)') m4_define(VAR, `SYMBOL()VALP()') -m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0; +m4_define(FRET, `m4_divert(2)if (f1->fret != f2->fret) return 0; m4_divert(-1)') -m4_define(ECS, `m4_divert(1)if (f1->ecs != f2->ecs) return 0; +m4_define(ECS, `m4_divert(2)if (f1->ecs != f2->ecs) return 0; m4_divert(-1)') -m4_define(RTC, `m4_divert(1)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0; +m4_define(RTC, `m4_divert(2)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0; m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(1)if (f1->sa.sa_code != f2->sa.sa_code) return 0; +m4_define(STATIC_ATTR, `m4_divert(2)if (f1->sa.sa_code != f2->sa.sa_code) return 0; m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(1)if (f1->da.ea_code != f2->da.ea_code) return 0; +m4_define(DYNAMIC_ATTR, `m4_divert(2)if (f1->da.ea_code != f2->da.ea_code) return 0; m4_divert(-1)') -m4_define(SAME, `m4_divert(1)$1m4_divert(-1)') +m4_define(SAME, `m4_divert(2)$1m4_divert(-1)') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -case FI_NOP: bug("This shall not happen"); m4_undivert(1) -break; default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff); +default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff); ') -m4_divert(1) m4_changequote([[,]]) diff --git a/filter/struct.m4 b/filter/struct.m4 index 66205bfd..7af28cfd 100644 --- a/filter/struct.m4 +++ b/filter/struct.m4 @@ -10,56 +10,62 @@ m4_divert(-1)m4_dnl # Common aliases m4_define(DNL, `m4_dnl') -m4_define(INST, `m4_divert(2)struct f_inst_$1 i_$1; -m4_divert(1)}; -struct f_inst_$1 { -m4_divert(-1)')) -m4_define(ARG, `m4_divert(1)const struct f_inst *f$1; +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +m4_divert(1) +struct f_inst_[[]]INST_NAME() { +m4_undivert(2) +}; +m4_divert(3) +struct f_inst_[[]]INST_NAME() i_[[]]INST_NAME(); +m4_divert(-1) +]])') +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') + +m4_define(ARG, `m4_divert(2)const struct f_inst *f$1; m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(1)const struct f_inst *f$1; +m4_define(ARG_ANY, `m4_divert(2)const struct f_inst *f$1; m4_divert(-1)') -m4_define(LINE, `m4_divert(1)const struct f_inst *f$1; +m4_define(LINE, `m4_divert(2)const struct f_inst *f$1; m4_divert(-1)') -m4_define(LINEP, `m4_divert(1)const struct f_line *fl$1; +m4_define(LINEP, `m4_divert(2)const struct f_line *fl$1; m4_divert(-1)') -m4_define(SYMBOL, `m4_divert(1)const struct symbol *sym; +m4_define(SYMBOL, `m4_divert(2)const struct symbol *sym; m4_divert(-1)') -m4_define(VALI, `m4_divert(1)struct f_val vali; +m4_define(VALI, `m4_divert(2)struct f_val vali; m4_divert(-1)') -m4_define(VALP, `m4_divert(1)const struct f_val *valp; +m4_define(VALP, `m4_divert(2)const struct f_val *valp; m4_divert(-1)') m4_define(VAR, `VALP()SYMBOL()') -m4_define(FRET, `m4_divert(1)enum filter_return fret; +m4_define(FRET, `m4_divert(2)enum filter_return fret; m4_divert(-1)') -m4_define(ECS, `m4_divert(1)enum ec_subtype ecs; +m4_define(ECS, `m4_divert(2)enum ec_subtype ecs; m4_divert(-1)') -m4_define(RTC, `m4_divert(1)const struct rtable_config *rtc; +m4_define(RTC, `m4_divert(2)const struct rtable_config *rtc; m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(1)struct f_static_attr sa; +m4_define(STATIC_ATTR, `m4_divert(2)struct f_static_attr sa; m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(1)struct f_dynamic_attr da; +m4_define(DYNAMIC_ATTR, `m4_divert(2)struct f_dynamic_attr da; m4_divert(-1)') -m4_define(COUNT, `m4_divert(1)uint count; +m4_define(COUNT, `m4_divert(2)uint count; m4_divert(-1)') -m4_define(TREE, `m4_divert(1)const struct f_tree *tree; +m4_define(TREE, `m4_divert(2)const struct f_tree *tree; m4_divert(-1)') -m4_define(STRING, `m4_divert(1)const char *s; +m4_define(STRING, `m4_divert(2)const char *s; m4_divert(-1)') -m4_define(STRUCT, `m4_divert(1)$1 +m4_define(STRUCT, `m4_divert(2)$1 m4_divert(-1)') m4_m4wrap(` +INST_FLUSH() m4_divert(0)DNL -struct f_inst_FI_NOP { m4_undivert(1) -}; struct f_inst { const struct f_inst *next; /* Next instruction */ enum f_instruction_code fi_code; /* Instruction code */ int lineno; /* Line number */ union { - m4_undivert(2) + m4_undivert(3) }; }; ') From 8bdb05edb2b4e1d2989ed98d67992047ad69443c Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 7 Feb 2019 21:25:38 +0100 Subject: [PATCH 21/88] Filters: split the large filter.h file to smaller files. This should be revised, there are still ugly things in the filter API. --- conf/cf-lex.l | 1 + filter/config.Y | 3 + filter/f-inst.h | 282 ++++++++++++++++++++++------------ filter/f-util.c | 2 +- filter/f-util.h | 151 ++++++++++++++++++ filter/filter.c | 38 ++++- filter/filter.h | 358 +------------------------------------------ filter/filter_test.c | 2 + filter/new.m4 | 2 +- filter/tree.c | 1 + filter/tree_test.c | 1 + filter/trie.c | 1 + filter/trie_test.c | 1 + nest/a-path.c | 2 +- nest/cmds.c | 1 + nest/rt-table.c | 1 + sysdep/unix/main.c | 1 + 17 files changed, 385 insertions(+), 463 deletions(-) create mode 100644 filter/f-util.h diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 5e7c8418..6cc09425 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -45,6 +45,7 @@ #include "nest/route.h" #include "nest/protocol.h" #include "filter/filter.h" +#include "filter/f-inst.h" #include "conf/conf.h" #include "conf/cf-parse.tab.h" #include "lib/string.h" diff --git a/filter/config.Y b/filter/config.Y index 1306849f..31ceb3f5 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -10,6 +10,9 @@ CF_HDR +#include "filter/f-inst.h" +#include "filter/f-util.h" + CF_DEFINES static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } diff --git a/filter/f-inst.h b/filter/f-inst.h index 5c3d1d58..63124aa1 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -1,76 +1,99 @@ /* * BIRD Internet Routing Daemon -- Filter instructions * + * (c) 1999 Pavel Machek * (c) 2018--2019 Maria Matejka * * Can be freely distributed and used under the terms of the GNU GPL. */ -/* Filter instruction words */ -#define FI__TWOCHAR(a,b) ((a<<8) | b) +#ifndef _BIRD_F_INST_H_ +#define _BIRD_F_INST_H_ + +#include "filter/filter.h" +#include "filter/f-util.h" + +/* Filter l-value type */ +enum f_lval_type { + F_LVAL_VARIABLE, + F_LVAL_PREFERENCE, + F_LVAL_SA, + F_LVAL_EA, +}; + +/* Filter l-value */ +struct f_lval { + enum f_lval_type type; + union { + const struct symbol *sym; + struct f_dynamic_attr da; + struct f_static_attr sa; + }; +}; + +/* Filter instruction declarations */ #define FI__LIST \ - F(FI_NOP, 0, '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_PATHMASK_CONSTRUCT, 'm', 'P') \ - 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_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_SADR_SRC, 'n', 's') \ - 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_DROP_RESULT, 'd', 'r') \ - F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \ - F(FI_SWITCH, 'S', 'W') \ - F(FI_IP_MASK, 'i', 'M') \ - F(FI_PATH_PREPEND, 'A', 'p') \ - F(FI_CLIST_ADD, 'C', 'a') \ - F(FI_CLIST_DEL, 'C', 'd') \ - F(FI_CLIST_FILTER, 'C', 'f') \ - F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \ - F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \ - F(FI_FORMAT, 0, 'F') \ - F(FI_ASSERT, 'a', 's') + F(FI_NOP) \ + F(FI_ADD, ARG, ARG) \ + F(FI_SUBTRACT, ARG, ARG) \ + F(FI_MULTIPLY, ARG, ARG) \ + F(FI_DIVIDE, ARG, ARG) \ + F(FI_AND, ARG, LINE) \ + F(FI_OR, ARG, LINE) \ + F(FI_PAIR_CONSTRUCT, ARG, ARG) \ + F(FI_EC_CONSTRUCT, ARG, ARG, ECS) \ + F(FI_LC_CONSTRUCT, ARG, ARG, ARG) \ + F(FI_PATHMASK_CONSTRUCT, ARG, COUNT) \ + F(FI_NEQ, ARG, ARG) \ + F(FI_EQ, ARG, ARG) \ + F(FI_LT, ARG, ARG) \ + F(FI_LTE, ARG, ARG) \ + F(FI_NOT, ARG) \ + F(FI_MATCH, ARG, ARG) \ + F(FI_NOT_MATCH, ARG, ARG) \ + F(FI_DEFINED, ARG) \ + F(FI_TYPE, ARG) \ + F(FI_IS_V4, ARG) \ + F(FI_SET, ARG, SYMBOL) \ + F(FI_CONSTANT, VALI) \ + F(FI_VARIABLE, SYMBOL) \ + F(FI_CONSTANT_INDIRECT, VALP) \ + F(FI_PRINT, ARG) \ + F(FI_CONDITION, ARG, LINE, LINE) \ + F(FI_PRINT_AND_DIE, ARG, FRET) \ + F(FI_RTA_GET, SA) \ + F(FI_RTA_SET, ARG, SA) \ + F(FI_EA_GET, EA) \ + F(FI_EA_SET, ARG, EA) \ + F(FI_EA_UNSET, EA) \ + F(FI_PREF_GET) \ + F(FI_PREF_SET, ARG) \ + F(FI_LENGTH, ARG) \ + F(FI_ROA_MAXLEN, ARG) \ + F(FI_ROA_ASN, ARG) \ + F(FI_SADR_SRC, ARG) \ + F(FI_IP, ARG) \ + F(FI_ROUTE_DISTINGUISHER, ARG) \ + F(FI_AS_PATH_FIRST, ARG) \ + F(FI_AS_PATH_LAST, ARG) \ + F(FI_AS_PATH_LAST_NAG, ARG) \ + F(FI_RETURN, ARG) \ + F(FI_CALL, SYMBOL, LINE) \ + F(FI_DROP_RESULT, ARG) \ + F(FI_SWITCH, ARG, TREE) \ + F(FI_IP_MASK, ARG, ARG) \ + F(FI_PATH_PREPEND, ARG, ARG) \ + F(FI_CLIST_ADD, ARG, ARG) \ + F(FI_CLIST_DEL, ARG, ARG) \ + F(FI_CLIST_FILTER, ARG, ARG) \ + F(FI_ROA_CHECK_IMPLICIT, RTC) \ + F(FI_ROA_CHECK_EXPLICIT, ARG, ARG, RTC) \ + F(FI_FORMAT, ARG) \ + F(FI_ASSERT, ARG, STRING) /* The enum itself */ enum f_instruction_code { -#define F(c,a,b) \ - c, +#define F(c, ...) c, FI__LIST #undef F FI__MAX, @@ -79,46 +102,107 @@ FI__LIST /* Convert the instruction back to the enum name */ const char *f_instruction_name(enum f_instruction_code fi); +struct f_inst; +void f_inst_next(struct f_inst *first, const struct f_inst *append); +struct f_inst *f_clear_local_vars(struct f_inst *decls); +#define FIA(x) , FIA_##x +#define FIA_ARG const struct f_inst * +#define FIA_LINE const struct f_inst * +#define FIA_COUNT uint +#define FIA_SYMBOL const struct symbol * +#define FIA_VALI struct f_val +#define FIA_VALP const struct f_val * +#define FIA_FRET enum filter_return +#define FIA_ECS enum ec_subtype +#define FIA_SA struct f_static_attr +#define FIA_EA struct f_dynamic_attr +#define FIA_RTC const struct rtable_config * +#define FIA_TREE const struct f_tree * +#define FIA_STRING const char * +#define F(c, ...) \ + struct f_inst *f_new_inst_##c(enum f_instruction_code MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))()(MACRO_FOREACH(FIA, __VA_ARGS__))); +FI__LIST +#undef F +#undef FIA_ARG +#undef FIA_LINE +#undef FIA_LINEP +#undef FIA_COUNT +#undef FIA_SYMBOL +#undef FIA_VALI +#undef FIA_VALP +#undef FIA_FRET +#undef FIA_ECS +#undef FIA_SA +#undef FIA_EA +#undef FIA_RTC +#undef FIA_STRING +#undef FIA -/* Instruction structure for config */ -struct f_inst { - const struct f_inst *next; /* Next instruction to be executed */ - union { /* Instruction content */ - struct { /* Instruction code for dispatching purposes */ - enum f_instruction_code fi_code; - }; +#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) - struct { - enum f_instruction_code fi_code_a; - const struct f_inst *p[3]; /* Three arguments at most */ - }; - - struct { - - - - struct { - enum f_instruction_code - - - - - enum f_iknst - u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ - union { - - union f_inst_attr a[3]; /* The three arguments */ - struct f_val val; /* The value if FI_CONSTANT */ - struct { - union f_inst_attr sa_a[1]; - struct f_static_attr sa; /* Static attribute def for FI_RTA_* */ - }; - struct { - union f_inst_attr da_a[1]; - struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */ - }; - }; - int lineno; +/* Flags for instructions */ +enum f_instruction_flags { + FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ }; +/* Filter structures for execution */ +struct f_line; + +/* The single instruction item */ +struct f_line_item { + enum f_instruction_code fi_code; /* What to do */ + enum f_instruction_flags flags; /* Flags, instruction-specific */ + uint lineno; /* Where */ + union { + struct { + const struct f_val *vp; + const struct symbol *sym; + }; + struct f_val val; + const struct f_line *lines[2]; + enum filter_return fret; + struct f_static_attr sa; + struct f_dynamic_attr da; + enum ec_subtype ecs; + const char *s; + const struct f_tree *tree; + const struct rtable_config *rtc; + uint count; + }; /* Additional instruction data */ +}; + +/* Line of instructions to be unconditionally executed one after another */ +struct f_line { + uint len; /* Line length */ + struct f_line_item items[0]; /* The items themselves */ +}; + +/* Convert the f_inst infix tree to the f_line structures */ +struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint count); +static inline struct f_line *f_postfixify(const struct f_inst *root) +{ return f_postfixify_concat(&root, 1); } + +struct filter *f_new_where(const struct f_inst *); +static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .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 }; } +struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); +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); + +/* Bird Tests */ +struct f_bt_test_suite { + node n; /* Node in config->tests */ + struct f_line *fn; /* Root of function */ + const char *fn_name; /* Name of test */ + const char *dsc; /* Description */ +}; + +/* Include the auto-generated structures */ +#include "filter/f-inst-struct.h" + +#endif diff --git a/filter/f-util.c b/filter/f-util.c index e94331b6..eb948fa0 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -10,7 +10,7 @@ #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-inst-struct.h" +#include "filter/f-inst.h" #include "lib/idm.h" #include "nest/protocol.h" #include "nest/route.h" diff --git a/filter/f-util.h b/filter/f-util.h new file mode 100644 index 00000000..a7d77bbd --- /dev/null +++ b/filter/f-util.h @@ -0,0 +1,151 @@ +/* + * BIRD Internet Routing Daemon -- Filter utils + * + * (c) 1999 Pavel Machek + * (c) 2018--2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_F_UTIL_H_ +#define _BIRD_F_UTIL_H_ + +/* IP prefix range structure */ +struct f_prefix { + net_addr net; /* The matching prefix must match this net */ + u8 lo, hi; /* And its length must fit between lo and hi */ +}; + +/* Type numbers must be in 0..0xff range */ +#define T_MASK 0xff + +/* Internal types */ +enum f_type { +/* Do not use type of zero, that way we'll see errors easier. */ + T_VOID = 1, + +/* User visible types, which fit in int */ + T_INT = 0x10, + T_BOOL = 0x11, + T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ + T_QUAD = 0x13, + +/* Put enumerational types in 0x30..0x3f range */ + T_ENUM_LO = 0x30, + T_ENUM_HI = 0x3f, + + T_ENUM_RTS = 0x30, + T_ENUM_BGP_ORIGIN = 0x31, + T_ENUM_SCOPE = 0x32, + T_ENUM_RTC = 0x33, + T_ENUM_RTD = 0x34, + T_ENUM_ROA = 0x35, + T_ENUM_NETTYPE = 0x36, + T_ENUM_RA_PREFERENCE = 0x37, + +/* new enums go here */ + T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */ + +#define T_ENUM T_ENUM_LO ... T_ENUM_HI + +/* Bigger ones */ + T_IP = 0x20, + T_NET = 0x21, + T_STRING = 0x22, + T_PATH_MASK = 0x23, /* mask for BGP path */ + T_PATH = 0x24, /* BGP path */ + T_CLIST = 0x25, /* Community list */ + T_EC = 0x26, /* Extended community value, u64 */ + T_ECLIST = 0x27, /* Extended community list */ + T_LC = 0x28, /* Large community value, lcomm */ + T_LCLIST = 0x29, /* Large community list */ + T_RD = 0x2a, /* Route distinguisher for VPN addresses */ + T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ + + T_SET = 0x80, + T_PREFIX_SET = 0x81, +} PACKED; + +/* Filter value; size of this affects filter memory consumption */ +struct f_val { + enum f_type type; /* T_* */ + union { + uint i; + u64 ec; + lcomm lc; + ip_addr ip; + const net_addr *net; + char *s; + const struct f_tree *t; + const struct f_trie *ti; + const struct adata *ad; + const struct f_path_mask *path_mask; + struct f_path_mask_item pmi; + } val; +}; + +#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); + +/* Dynamic attribute definition (eattrs) */ +struct f_dynamic_attr { + u8 type; /* EA type (EAF_*) */ + u8 bit; /* For bitfield accessors */ + enum f_type f_type; /* Filter type */ + uint ea_code; /* EA code */ +}; + +enum f_sa_code { + SA_FROM = 1, + SA_GW, + SA_NET, + SA_PROTO, + SA_SOURCE, + SA_SCOPE, + SA_DEST, + SA_IFNAME, + SA_IFINDEX, +} PACKED; + +/* Static attribute definition (members of struct rta) */ +struct f_static_attr { + enum f_type f_type; /* Filter type */ + enum f_sa_code sa_code; /* Static attribute id */ + int readonly:1; /* Don't allow writing */ +}; + +struct f_tree { + struct f_tree *left, *right; + struct f_val from, to; + void *data; +}; + +struct f_trie_node +{ + ip_addr addr, mask, accept; + uint plen; + struct f_trie_node *c[2]; +}; + +struct f_trie +{ + linpool *lp; + int zero; + uint node_size; + struct f_trie_node root[0]; /* Root trie node follows */ +}; + +struct f_tree *f_new_tree(void); +struct f_tree *build_tree(struct f_tree *); +const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); +int same_tree(const struct f_tree *t0, const struct f_tree *t2); +void tree_format(const struct f_tree *t, buffer *buf); + +struct f_trie *f_new_trie(linpool *lp, uint node_size); +void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); +int trie_match_net(const struct f_trie *t, const net_addr *n); +int trie_same(const struct f_trie *t1, const struct f_trie *t2); +void trie_format(const struct f_trie *t, buffer *buf); + +extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; + +#endif diff --git a/filter/filter.c b/filter/filter.c index bb5e4235..ff702f2b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -47,7 +47,8 @@ #include "nest/attrs.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-inst-struct.h" +#include "filter/f-inst.h" +#include "filter/f-util.h" #define CMP_ERROR 999 @@ -715,12 +716,39 @@ f_postfixify_concat(const struct f_inst * const inst[], uint count) static enum filter_return interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) { - struct f_val_stack vstk; - vstk.cnt = 0; - struct f_exec_stack estk; +#define F_VAL_STACK_MAX 4096 + /* Value stack for execution */ + struct f_val_stack { + uint cnt; /* Current stack size; 0 for empty */ + struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */ + } vstk; + + /* The stack itself is intentionally kept as-is for performance reasons. + * Do NOT rewrite this to initialization by struct literal. It's slow. + */ + vstk.cnt = 0; +#define F_EXEC_STACK_MAX 4096 + + /* Exception bits */ + enum f_exception { + FE_RETURN = 0x1, + }; + + /* Instruction stack for execution */ + struct f_exec_stack { + struct { + const struct f_line *line; /* The line that is being executed */ + uint pos; /* Instruction index in the line */ + uint ventry; /* Value stack depth on entry */ + enum f_exception emask; /* Exception mask */ + } item[F_EXEC_STACK_MAX]; + uint cnt; /* Current stack size; 0 for empty */ + } estk; + + /* The same as with the value stack. Not resetting the stack for performance reasons. */ estk.cnt = 1; - estk.item[0].line = line; + estk.item[0].line = line; estk.item[0].pos = 0; #define curline estk.item[estk.cnt-1] diff --git a/filter/filter.h b/filter/filter.h index 15a24fd4..9b3886fb 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -16,107 +16,6 @@ #include "nest/route.h" #include "nest/attrs.h" -/* IP prefix range structure */ -struct f_prefix { - net_addr net; /* The matching prefix must match this net */ - u8 lo, hi; /* And its length must fit between lo and hi */ -}; - -/* Type numbers must be in 0..0xff range */ -#define T_MASK 0xff - -/* Internal types */ -enum f_type { -/* Do not use type of zero, that way we'll see errors easier. */ - T_VOID = 1, - -/* User visible types, which fit in int */ - T_INT = 0x10, - T_BOOL = 0x11, - T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ - T_QUAD = 0x13, - -/* Put enumerational types in 0x30..0x3f range */ - T_ENUM_LO = 0x30, - T_ENUM_HI = 0x3f, - - T_ENUM_RTS = 0x30, - T_ENUM_BGP_ORIGIN = 0x31, - T_ENUM_SCOPE = 0x32, - T_ENUM_RTC = 0x33, - T_ENUM_RTD = 0x34, - T_ENUM_ROA = 0x35, - T_ENUM_NETTYPE = 0x36, - T_ENUM_RA_PREFERENCE = 0x37, - -/* new enums go here */ - T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */ - -#define T_ENUM T_ENUM_LO ... T_ENUM_HI - -/* Bigger ones */ - T_IP = 0x20, - T_NET = 0x21, - T_STRING = 0x22, - T_PATH_MASK = 0x23, /* mask for BGP path */ - T_PATH = 0x24, /* BGP path */ - T_CLIST = 0x25, /* Community list */ - T_EC = 0x26, /* Extended community value, u64 */ - T_ECLIST = 0x27, /* Extended community list */ - T_LC = 0x28, /* Large community value, lcomm */ - T_LCLIST = 0x29, /* Large community list */ - T_RD = 0x2a, /* Route distinguisher for VPN addresses */ - T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ - - T_SET = 0x80, - T_PREFIX_SET = 0x81, -} PACKED; - -/* Filter value; size of this affects filter memory consumption */ -struct f_val { - enum f_type type; /* T_* */ - union { - uint i; - u64 ec; - lcomm lc; - ip_addr ip; - const net_addr *net; - char *s; - const struct f_tree *t; - const struct f_trie *ti; - const struct adata *ad; - const struct f_path_mask *path_mask; - struct f_path_mask_item pmi; - } val; -}; - -/* Dynamic attribute definition (eattrs) */ -struct f_dynamic_attr { - u8 type; /* EA type (EAF_*) */ - u8 bit; /* For bitfield accessors */ - enum f_type f_type; /* Filter type */ - uint ea_code; /* EA code */ -}; - -enum f_sa_code { - SA_FROM = 1, - SA_GW, - SA_NET, - SA_PROTO, - SA_SOURCE, - SA_SCOPE, - SA_DEST, - SA_IFNAME, - SA_IFINDEX, -} PACKED; - -/* Static attribute definition (members of struct rta) */ -struct f_static_attr { - enum f_type f_type; /* Filter type */ - enum f_sa_code sa_code; /* Static attribute id */ - int readonly:1; /* Don't allow writing */ -}; - /* Possible return values of filter execution */ enum filter_return { F_NOP = 0, @@ -128,230 +27,15 @@ enum filter_return { F_QUITBIRD, }; -/* Filter l-value type */ -enum f_lval_type { - F_LVAL_VARIABLE, - F_LVAL_PREFERENCE, - F_LVAL_SA, - F_LVAL_EA, -}; - -/* Filter l-value */ -struct f_lval { - enum f_lval_type type; - union { - const struct symbol *sym; - struct f_dynamic_attr da; - struct f_static_attr sa; - }; -}; - -/* Filter instruction declarations */ -#define FI__LIST \ - F(FI_NOP) \ - F(FI_ADD, ARG, ARG) \ - F(FI_SUBTRACT, ARG, ARG) \ - F(FI_MULTIPLY, ARG, ARG) \ - F(FI_DIVIDE, ARG, ARG) \ - F(FI_AND, ARG, LINE) \ - F(FI_OR, ARG, LINE) \ - F(FI_PAIR_CONSTRUCT, ARG, ARG) \ - F(FI_EC_CONSTRUCT, ARG, ARG, ECS) \ - F(FI_LC_CONSTRUCT, ARG, ARG, ARG) \ - F(FI_PATHMASK_CONSTRUCT, ARG, COUNT) \ - F(FI_NEQ, ARG, ARG) \ - F(FI_EQ, ARG, ARG) \ - F(FI_LT, ARG, ARG) \ - F(FI_LTE, ARG, ARG) \ - F(FI_NOT, ARG) \ - F(FI_MATCH, ARG, ARG) \ - F(FI_NOT_MATCH, ARG, ARG) \ - F(FI_DEFINED, ARG) \ - F(FI_TYPE, ARG) \ - F(FI_IS_V4, ARG) \ - F(FI_SET, ARG, SYMBOL) \ - F(FI_CONSTANT, VALI) \ - F(FI_VARIABLE, SYMBOL) \ - F(FI_CONSTANT_INDIRECT, VALP) \ - F(FI_PRINT, ARG) \ - F(FI_CONDITION, ARG, LINE, LINE) \ - F(FI_PRINT_AND_DIE, ARG, FRET) \ - F(FI_RTA_GET, SA) \ - F(FI_RTA_SET, ARG, SA) \ - F(FI_EA_GET, EA) \ - F(FI_EA_SET, ARG, EA) \ - F(FI_EA_UNSET, EA) \ - F(FI_PREF_GET) \ - F(FI_PREF_SET, ARG) \ - F(FI_LENGTH, ARG) \ - F(FI_ROA_MAXLEN, ARG) \ - F(FI_ROA_ASN, ARG) \ - F(FI_SADR_SRC, ARG) \ - F(FI_IP, ARG) \ - F(FI_ROUTE_DISTINGUISHER, ARG) \ - F(FI_AS_PATH_FIRST, ARG) \ - F(FI_AS_PATH_LAST, ARG) \ - F(FI_AS_PATH_LAST_NAG, ARG) \ - F(FI_RETURN, ARG) \ - F(FI_CALL, SYMBOL, LINE) \ - F(FI_DROP_RESULT, ARG) \ - F(FI_SWITCH, ARG, TREE) \ - F(FI_IP_MASK, ARG, ARG) \ - F(FI_PATH_PREPEND, ARG, ARG) \ - F(FI_CLIST_ADD, ARG, ARG) \ - F(FI_CLIST_DEL, ARG, ARG) \ - F(FI_CLIST_FILTER, ARG, ARG) \ - F(FI_ROA_CHECK_IMPLICIT, RTC) \ - F(FI_ROA_CHECK_EXPLICIT, ARG, ARG, RTC) \ - F(FI_FORMAT, ARG) \ - F(FI_ASSERT, ARG, STRING) - -/* The enum itself */ -enum f_instruction_code { -#define F(c, ...) c, -FI__LIST -#undef F - FI__MAX, -} PACKED; - -/* Convert the instruction back to the enum name */ -const char *f_instruction_name(enum f_instruction_code fi); - -struct f_inst; -void f_inst_next(struct f_inst *first, const struct f_inst *append); -struct f_inst *f_clear_local_vars(struct f_inst *decls); - -#define FIA(x) , FIA_##x -#define FIA_ARG const struct f_inst * -#define FIA_LINE const struct f_inst * -#define FIA_COUNT uint -#define FIA_SYMBOL const struct symbol * -#define FIA_VALI struct f_val -#define FIA_VALP const struct f_val * -#define FIA_FRET enum filter_return -#define FIA_ECS enum ec_subtype -#define FIA_SA struct f_static_attr -#define FIA_EA struct f_dynamic_attr -#define FIA_RTC const struct rtable_config * -#define FIA_TREE const struct f_tree * -#define FIA_STRING const char * -#define F(c, ...) \ - struct f_inst *f_new_inst_##c(enum f_instruction_code MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))()(MACRO_FOREACH(FIA, __VA_ARGS__))); -FI__LIST -#undef F -#undef FIA_ARG -#undef FIA_LINE -#undef FIA_LINEP -#undef FIA_COUNT -#undef FIA_SYMBOL -#undef FIA_VALI -#undef FIA_VALP -#undef FIA_FRET -#undef FIA_ECS -#undef FIA_SA -#undef FIA_EA -#undef FIA_RTC -#undef FIA_STRING -#undef FIA - -#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) - -/* Flags for instructions */ -enum f_instruction_flags { - FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ -}; - -/* Filter structures for execution */ -struct f_line; - -/* The single instruction item */ -struct f_line_item { - enum f_instruction_code fi_code; /* What to do */ - enum f_instruction_flags flags; /* Flags, instruction-specific */ - uint lineno; /* Where */ - union { - struct { - const struct f_val *vp; - const struct symbol *sym; - }; - struct f_val val; - const struct f_line *lines[2]; - enum filter_return fret; - struct f_static_attr sa; - struct f_dynamic_attr da; - enum ec_subtype ecs; - const char *s; - const struct f_tree *tree; - const struct rtable_config *rtc; - uint count; - }; /* Additional instruction data */ -}; - -/* Line of instructions to be unconditionally executed one after another */ -struct f_line { - uint len; /* Line length */ - struct f_line_item items[0]; /* The items themselves */ -}; +struct f_val; /* The filter encapsulating structure to be pointed-to from outside */ +struct f_line; struct filter { char *name; struct f_line *root; }; -/* Convert the f_inst infix tree to the f_line structures */ -struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint count); -static inline struct f_line *f_postfixify(const struct f_inst *root) -{ return f_postfixify_concat(&root, 1); } - -#define F_VAL_STACK_MAX 4096 - -/* Value stack for execution */ -struct f_val_stack { - uint cnt; /* Current stack size; 0 for empty */ - struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */ -}; - -#define F_EXEC_STACK_MAX 4096 - -/* Exception bits */ -enum f_exception { - FE_RETURN = 0x1, -}; - -/* Instruction stack for execution */ -struct f_exec_stack { - struct { - const struct f_line *line; /* The line that is being executed */ - uint pos; /* Instruction index in the line */ - uint ventry; /* Value stack depth on entry */ - enum f_exception emask; /* Exception mask */ - } item[F_EXEC_STACK_MAX]; - uint cnt; /* Current stack size; 0 for empty */ -}; - -struct filter *f_new_where(const struct f_inst *); -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .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 }; } -struct f_tree *f_new_tree(void); -struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); -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 *); -const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); -int same_tree(const struct f_tree *t1, const struct f_tree *t2); -void tree_format(const struct f_tree *t, buffer *buf); - -struct f_trie *f_new_trie(linpool *lp, uint node_size); -void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); -int trie_match_net(const struct f_trie *t, const net_addr *n); -int trie_same(const struct f_trie *t1, const struct f_trie *t2); -void trie_format(const struct f_trie *t, buffer *buf); - -struct ea_list; struct rte; enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); @@ -361,43 +45,16 @@ uint f_eval_int(const struct f_line *expr); char *filter_name(struct filter *filter); int filter_same(struct filter *new, struct filter *old); - int f_same(const struct f_line *f1, const struct f_line *f2); int val_compare(const struct f_val *v1, const struct f_val *v2); void val_format(const struct f_val *v, buffer *buf); -extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; - #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) #define FILTER_UNDEF ((void *) 2) /* Used in BGP */ - -struct f_tree { - struct f_tree *left, *right; - struct f_val from, to; - void *data; -}; - -struct f_trie_node -{ - ip_addr addr, mask, accept; - uint plen; - struct f_trie_node *c[2]; -}; - -struct f_trie -{ - linpool *lp; - int zero; - uint node_size; - struct f_trie_node root[0]; /* Root trie node follows */ -}; - -#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); - #define FF_SILENT 2 /* Silent filter execution */ /* Custom route attributes */ @@ -409,15 +66,4 @@ struct custom_attribute { struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type); -/* Bird Tests */ -struct f_bt_test_suite { - node n; /* Node in config->tests */ - struct f_line *fn; /* Root of function */ - const char *fn_name; /* Name of test */ - const char *dsc; /* Description */ -}; - -/* Hook for call bt_assert() function in configuration */ -extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); - #endif diff --git a/filter/filter_test.c b/filter/filter_test.c index af6b590f..54ea3e9b 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -17,6 +17,8 @@ #include "test/bt-utils.h" #include "filter/filter.h" +#include "filter/f-util.h" +#include "filter/f-inst.h" #include "conf/conf.h" #define BT_CONFIG_FILE "filter/test.conf" diff --git a/filter/new.m4 b/filter/new.m4 index d499c94b..38295e5c 100644 --- a/filter/new.m4 +++ b/filter/new.m4 @@ -69,7 +69,7 @@ m4_divert(0) #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-inst-struct.h" +#include "filter/f-inst.h" m4_undivert(1) diff --git a/filter/tree.c b/filter/tree.c index 80e1d395..879b0859 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -10,6 +10,7 @@ #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-util.h" /** * find_tree diff --git a/filter/tree_test.c b/filter/tree_test.c index f3e8ce49..9e0de50f 100644 --- a/filter/tree_test.c +++ b/filter/tree_test.c @@ -10,6 +10,7 @@ #include "test/bt-utils.h" #include "filter/filter.h" +#include "filter/f-util.h" #include "conf/conf.h" #define MAX_TREE_HEIGHT 13 diff --git a/filter/trie.c b/filter/trie.c index a279e38c..dccf9130 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -73,6 +73,7 @@ #include "lib/string.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-util.h" /* diff --git a/filter/trie_test.c b/filter/trie_test.c index 7529a5c5..b6959c4a 100644 --- a/filter/trie_test.c +++ b/filter/trie_test.c @@ -10,6 +10,7 @@ #include "test/bt-utils.h" #include "filter/filter.h" +#include "filter/f-util.h" #include "conf/conf.h" #define TESTS_NUM 10 diff --git a/nest/a-path.c b/nest/a-path.c index d3a1d636..ac13d0fa 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -13,7 +13,7 @@ #include "lib/resource.h" #include "lib/unaligned.h" #include "lib/string.h" -#include "filter/filter.h" +#include "filter/f-util.h" // static inline void put_as(byte *data, u32 as) { put_u32(data, as); } // static inline u32 get_as(byte *data) { return get_u32(data); } diff --git a/nest/cmds.c b/nest/cmds.c index 6daafcb3..40d397cc 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -15,6 +15,7 @@ #include "lib/string.h" #include "lib/resource.h" #include "filter/filter.h" +#include "filter/f-util.h" extern int shutting_down; extern int configuring; diff --git a/nest/rt-table.c b/nest/rt-table.c index 85afe838..d72a8695 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -39,6 +39,7 @@ #include "lib/string.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-util.h" #include "lib/hash.h" #include "lib/string.h" #include "lib/alloca.h" diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 921115b1..f9002d58 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -36,6 +36,7 @@ #include "nest/locks.h" #include "conf/conf.h" #include "filter/filter.h" +#include "filter/f-util.h" #include "unix.h" #include "krt.h" From 0a793ebc6059f4354c62ccec62ef7c950988ca4a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 8 Feb 2019 11:19:04 +0100 Subject: [PATCH 22/88] Test: Fixed annoying warnings (and possible obscure bugs). --- filter/filter_test.c | 2 +- test/birdtest.c | 5 +---- test/birdtest.h | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/filter/filter_test.c b/filter/filter_test.c index 54ea3e9b..a02f0832 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -35,7 +35,7 @@ parse_config_file(const void *argv) const struct parse_config_file_arg *arg = argv; size_t fn_size = strlen(arg->filename) + 1; char *filename = alloca(fn_size); - strncpy(filename, arg->filename, fn_size); + memcpy(filename, arg->filename, fn_size); *(arg->cp) = bt_config_file_parse(filename); return !!*(arg->cp); diff --git a/test/birdtest.c b/test/birdtest.c index a4312e9b..347f79b9 100644 --- a/test/birdtest.c +++ b/test/birdtest.c @@ -155,10 +155,7 @@ int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout) int result; alarm(timeout); - if (fn_arg) - result = fn(fn_arg); - else - result = ((int (*)(void))fn)(); + result = fn(fn_arg); if (!bt_suite_result) result = 0; diff --git a/test/birdtest.h b/test/birdtest.h index 4443bfc1..18228711 100644 --- a/test/birdtest.h +++ b/test/birdtest.h @@ -54,11 +54,13 @@ void bt_log_suite_case_result(int result, const char *fmt, ...); #define BT_PROMPT_FAIL_NO_COLOR " [" "FAIL" "] " #define BT_PROMPT_OK_FAIL_STRLEN 8 /* strlen ' [FAIL] ' */ +static inline int bt_test_fn_noarg(const void *cp) { return ((int (*)(void)) cp)(); } + #define bt_test_suite(fn, dsc, ...) \ bt_test_suite_extra(fn, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__) #define bt_test_suite_extra(fn, f, t, dsc, ...) \ - bt_test_suite_base((int (*)(const void *))fn, #fn, NULL, f, t, dsc, ##__VA_ARGS__) + bt_test_suite_base(bt_test_fn_noarg, #fn, fn, f, t, dsc, ##__VA_ARGS__) #define bt_test_suite_arg(fn, arg, dsc, ...) \ bt_test_suite_arg_extra(fn, arg, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__) From 4f082dfa892e95f86ca8137410992a248110b6ef Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 8 Feb 2019 13:38:12 +0100 Subject: [PATCH 23/88] Filter: merged filter instruction constructors, counting line size on instruction construct --- configure.ac | 8 ++- filter/Makefile | 12 +--- filter/config.Y | 24 +++---- filter/{f-util.h => data.h} | 38 ++++++++--- filter/decl.m4 | 128 +++++++++++++++++++++++++++++++++++ filter/f-inst.c | 36 +++++----- filter/f-inst.h | 131 ++---------------------------------- filter/f-util.c | 19 +----- filter/filter.c | 86 +++++++++++++++++++---- filter/filter_test.c | 2 +- filter/interpret.m4 | 7 +- filter/line-size.m4 | 41 ----------- filter/new.m4 | 78 --------------------- filter/struct.m4 | 73 -------------------- filter/tree.c | 2 +- filter/tree_test.c | 2 +- filter/trie.c | 2 +- filter/trie_test.c | 2 +- nest/a-path.c | 2 +- nest/cmds.c | 2 +- nest/rt-table.c | 2 +- proto/static/config.Y | 2 +- sysdep/unix/main.c | 2 +- 23 files changed, 291 insertions(+), 410 deletions(-) rename filter/{f-util.h => data.h} (89%) create mode 100644 filter/decl.m4 delete mode 100644 filter/line-size.m4 delete mode 100644 filter/new.m4 delete mode 100644 filter/struct.m4 diff --git a/configure.ac b/configure.ac index 33bc9101..850e771f 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,12 @@ AC_ARG_ENABLE([debug], [enable_debug=no] ) +AC_ARG_ENABLE([debug-generated], + [AS_HELP_STRING([--enable-debug-generated], [enable this to abstain from generating #line @<:@no@:>@])], + [], + [enable_debug_generated=no] +) + AC_ARG_ENABLE([memcheck], [AS_HELP_STRING([--enable-memcheck], [check memory allocations when debugging @<:@yes@:>@])], [], @@ -156,7 +162,7 @@ test -z "$M4" && AC_MSG_ERROR([M4 is missing.]) AC_MSG_CHECKING([bison version]) BIRD_CHECK_BISON_VERSION(BISON_VERSION) AC_MSG_RESULT([$BISON_VERSION]) -if test "$bird_bison_synclines" = yes; then +if test "$bird_bison_synclines" = yes && test "$enable_debug_generated" = no; then M4FLAGS="$M4FLAGS -s" fi diff --git a/filter/Makefile b/filter/Makefile index 15f2c3d0..f5f50045 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,13 +1,10 @@ -src := filter.c f-util.c tree.c trie.c f-inst-new.c +src := filter.c f-util.c tree.c trie.c obj := $(src-o-files) $(all-daemon) $(cf-local) M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) -$(o)f-inst-line-size.c: $(s)line-size.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - $(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ @@ -17,16 +14,13 @@ $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)f-inst-struct.h: $(s)struct.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - -$(o)f-inst-new.c: $(s)new.m4 $(s)f-inst.c $(objdir)/.dir-stamp +$(o)f-inst-decl.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ $(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)f-inst-struct.h +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)f-inst-decl.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/config.Y b/filter/config.Y index 31ceb3f5..42624f44 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -11,7 +11,7 @@ CF_HDR #include "filter/f-inst.h" -#include "filter/f-util.h" +#include "filter/data.h" CF_DEFINES @@ -418,7 +418,7 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const } checker = f_new_inst(FI_EQ, expr, getter); - f_inst_next(setter, checker); + setter->next = checker; return assert_done(setter, start, end); } @@ -550,7 +550,7 @@ one_decl: decls: /* EMPTY */ { $$ = NULL; } | one_decl ';' decls { $$ = $1; - f_inst_next($$, $3); + $$->next = $3; } ; @@ -559,7 +559,7 @@ declsn: one_decl { $$.inst = $1; $$.count = 1; } | one_decl ';' declsn { $$ = $3; $$.count++; - f_inst_next($$.inst, $1); + $$.inst->next = $1; } ; @@ -640,7 +640,7 @@ cmds: /* EMPTY */ { $$ = NULL; } ; cmds_int: cmd { $$[0] = $$[1] = $1; } - | cmds_int cmd { $$[1] = $2; f_inst_next($1[1], $2); $$[0] = $1[0]; } + | cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; } ; block: @@ -803,11 +803,11 @@ bgp_path: ; bgp_path_tail: - NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); f_inst_next($$, $2); } - | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); f_inst_next($$, $4); } - | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); f_inst_next($$, $2); } - | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); f_inst_next($$, $2); } - | bgp_path_expr bgp_path_tail { $$ = $1; f_inst_next($$, $2); } + NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; } + | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; } + | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; } + | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; } + | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; } | { $$ = NULL; } ; @@ -946,7 +946,7 @@ print_list: /* EMPTY */ { $$ = NULL; } | print_one { $$ = $1; } | print_one ',' print_list { if ($1) { - f_inst_next($1, $3); + $1->next = $3; $$ = $1; } else $$ = $3; } @@ -957,7 +957,7 @@ var_listn: term { } | term ',' var_listn { $$ = $1; - f_inst_next($$, $3); + $$->next = $3; } ; diff --git a/filter/f-util.h b/filter/data.h similarity index 89% rename from filter/f-util.h rename to filter/data.h index a7d77bbd..58db3e44 100644 --- a/filter/f-util.h +++ b/filter/data.h @@ -1,5 +1,5 @@ /* - * BIRD Internet Routing Daemon -- Filter utils + * BIRD Internet Routing Daemon -- Dynamic data structures * * (c) 1999 Pavel Machek * (c) 2018--2019 Maria Matejka @@ -7,14 +7,10 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ -#ifndef _BIRD_F_UTIL_H_ -#define _BIRD_F_UTIL_H_ +#ifndef _BIRD_FILTER_DATA_H_ +#define _BIRD_FILTER_DATA_H_ -/* IP prefix range structure */ -struct f_prefix { - net_addr net; /* The matching prefix must match this net */ - u8 lo, hi; /* And its length must fit between lo and hi */ -}; +#include "nest/bird.h" /* Type numbers must be in 0..0xff range */ #define T_MASK 0xff @@ -84,8 +80,6 @@ struct f_val { } val; }; -#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); - /* Dynamic attribute definition (eattrs) */ struct f_dynamic_attr { u8 type; /* EA type (EAF_*) */ @@ -113,6 +107,30 @@ struct f_static_attr { int readonly:1; /* Don't allow writing */ }; +/* Filter l-value type */ +enum f_lval_type { + F_LVAL_VARIABLE, + F_LVAL_PREFERENCE, + F_LVAL_SA, + F_LVAL_EA, +}; + +/* Filter l-value */ +struct f_lval { + enum f_lval_type type; + union { + const struct symbol *sym; + struct f_dynamic_attr da; + struct f_static_attr sa; + }; +}; + +/* IP prefix range structure */ +struct f_prefix { + net_addr net; /* The matching prefix must match this net */ + u8 lo, hi; /* And its length must fit between lo and hi */ +}; + struct f_tree { struct f_tree *left, *right; struct f_val from, to; diff --git a/filter/decl.m4 b/filter/decl.m4 new file mode 100644 index 00000000..bdbb3e27 --- /dev/null +++ b/filter/decl.m4 @@ -0,0 +1,128 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Construction of per-instruction structures +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# +# +# Global Diversions: +# 4 enum fi_code +# 1 struct f_inst_FI_... +# 2 union in struct f_inst +# 3 constructors +# +# Per-inst Diversions: +# 11 content of struct f_inst_FI_... +# 12 constructor arguments +# 13 constructor body + +# Flush the completed instruction + +m4_define(FID_END, `m4_divert(-1)') + +m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') +m4_define(FID_STRUCT, `FID_ZONE(1, Per-instruction structure)') +m4_define(FID_UNION, `FID_ZONE(2, Union member)') +m4_define(FID_NEW, `FID_ZONE(3, Constructor)') +m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') + +m4_define(FID_STRUCT_IN, `m4_divert(101)') +m4_define(FID_NEW_ARGS, `m4_divert(102)') +m4_define(FID_NEW_BODY, `m4_divert(103)') + +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +FID_ENUM +INST_NAME(), +FID_STRUCT +struct f_inst_[[]]INST_NAME() { +m4_undivert(101) +}; +FID_UNION +struct f_inst_[[]]INST_NAME() i_[[]]INST_NAME(); +FID_NEW +static inline struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +m4_undivert(102) +) { + struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); + what_->fi_code = fi_code; + what_->lineno = ifs->lino; + what_->size = 1; + struct f_inst_[[]]INST_NAME() *what UNUSED = &(what_->i_[[]]INST_NAME()); +m4_undivert(103) + return what_; +} +FID_END +]])') + +m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') + +m4_define(FID_MEMBER, `m4_dnl +FID_STRUCT_IN +$1 $2; +FID_NEW_ARGS +, $1 $2 +FID_NEW_BODY +what->$2 = $2; +FID_END') + +m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1) +FID_NEW_BODY +for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; +FID_END') +m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1) +FID_NEW_BODY +for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; +FID_END') +m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1)') +m4_define(LINEP, `FID_STRUCT_IN +const struct f_line *fl$1; +FID_END') +m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym)') +m4_define(VALI, `FID_MEMBER(struct f_val, vali)') +m4_define(VALP, `FID_MEMBER(const struct f_val *, valp)') +m4_define(VAR, `m4_dnl +FID_STRUCT_IN +const struct f_val *valp; +const struct symbol *sym; +FID_NEW_ARGS +, const struct symbol *sym +FID_NEW_BODY +what->valp = (what->sym = sym)->def; +FID_END') +m4_define(FRET, `FID_MEMBER(enum filter_return, fret)') +m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs)') +m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc)') +m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da)') +m4_define(COUNT, `FID_MEMBER(uint, count)') +m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree)') +m4_define(STRING, `FID_MEMBER(const char *, s)') + +m4_m4wrap(` +INST_FLUSH() +m4_divert(0) +/* Filter instruction codes */ +enum f_instruction_code { +m4_undivert(4) +}; + +/* Per-instruction structures */ +m4_undivert(1) + +struct f_inst { + const struct f_inst *next; /* Next instruction */ + enum f_instruction_code fi_code; /* Instruction code */ + int size; /* How many instructions are underneath */ + int lineno; /* Line number */ + union { + m4_undivert(2) + }; +}; + +/* Instruction constructors */ +m4_undivert(3) +') + +m4_changequote([[,]]) diff --git a/filter/f-inst.c b/filter/f-inst.c index 0dd9f9f6..afb895c5 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -109,15 +109,15 @@ ARG_ANY(1); COUNT(2); - NEW(, [[ - uint len = 0; - uint dyn = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) - if (tt->fi_code != FI_CONSTANT) - dyn++; + FID_NEW_BODY + uint len = 0; + uint dyn = 0; + for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) + if (tt->fi_code != FI_CONSTANT) + dyn++; - WHAT().count = len; - ]]); + what->count = len; + FID_END if (vstk.cnt < what->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count); @@ -719,17 +719,17 @@ /* Then push the arguments */ LINE(1,1); - NEW(, [[ - if (sym->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); + FID_NEW_BODY + if (sym->class != SYM_FUNCTION) + cf_error("You can't call something which is not a function. Really."); - uint count = 0; - for (const struct f_inst *inst = f1; inst; inst = inst->next) - count++; - - if (count != sym->aux2) - cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); - ]]); + uint count = 0; + for (const struct f_inst *inst = f1; inst; inst = inst->next) + count++; + + if (count != sym->aux2) + cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); + FID_END } INST(FI_DROP_RESULT, 1, 0) { diff --git a/filter/f-inst.h b/filter/f-inst.h index 63124aa1..1423e685 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -10,137 +10,21 @@ #ifndef _BIRD_F_INST_H_ #define _BIRD_F_INST_H_ +#include "nest/bird.h" +#include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" -/* Filter l-value type */ -enum f_lval_type { - F_LVAL_VARIABLE, - F_LVAL_PREFERENCE, - F_LVAL_SA, - F_LVAL_EA, -}; +/* Include generated filter instruction declarations */ +#include "filter/f-inst-decl.h" -/* Filter l-value */ -struct f_lval { - enum f_lval_type type; - union { - const struct symbol *sym; - struct f_dynamic_attr da; - struct f_static_attr sa; - }; -}; - -/* Filter instruction declarations */ -#define FI__LIST \ - F(FI_NOP) \ - F(FI_ADD, ARG, ARG) \ - F(FI_SUBTRACT, ARG, ARG) \ - F(FI_MULTIPLY, ARG, ARG) \ - F(FI_DIVIDE, ARG, ARG) \ - F(FI_AND, ARG, LINE) \ - F(FI_OR, ARG, LINE) \ - F(FI_PAIR_CONSTRUCT, ARG, ARG) \ - F(FI_EC_CONSTRUCT, ARG, ARG, ECS) \ - F(FI_LC_CONSTRUCT, ARG, ARG, ARG) \ - F(FI_PATHMASK_CONSTRUCT, ARG, COUNT) \ - F(FI_NEQ, ARG, ARG) \ - F(FI_EQ, ARG, ARG) \ - F(FI_LT, ARG, ARG) \ - F(FI_LTE, ARG, ARG) \ - F(FI_NOT, ARG) \ - F(FI_MATCH, ARG, ARG) \ - F(FI_NOT_MATCH, ARG, ARG) \ - F(FI_DEFINED, ARG) \ - F(FI_TYPE, ARG) \ - F(FI_IS_V4, ARG) \ - F(FI_SET, ARG, SYMBOL) \ - F(FI_CONSTANT, VALI) \ - F(FI_VARIABLE, SYMBOL) \ - F(FI_CONSTANT_INDIRECT, VALP) \ - F(FI_PRINT, ARG) \ - F(FI_CONDITION, ARG, LINE, LINE) \ - F(FI_PRINT_AND_DIE, ARG, FRET) \ - F(FI_RTA_GET, SA) \ - F(FI_RTA_SET, ARG, SA) \ - F(FI_EA_GET, EA) \ - F(FI_EA_SET, ARG, EA) \ - F(FI_EA_UNSET, EA) \ - F(FI_PREF_GET) \ - F(FI_PREF_SET, ARG) \ - F(FI_LENGTH, ARG) \ - F(FI_ROA_MAXLEN, ARG) \ - F(FI_ROA_ASN, ARG) \ - F(FI_SADR_SRC, ARG) \ - F(FI_IP, ARG) \ - F(FI_ROUTE_DISTINGUISHER, ARG) \ - F(FI_AS_PATH_FIRST, ARG) \ - F(FI_AS_PATH_LAST, ARG) \ - F(FI_AS_PATH_LAST_NAG, ARG) \ - F(FI_RETURN, ARG) \ - F(FI_CALL, SYMBOL, LINE) \ - F(FI_DROP_RESULT, ARG) \ - F(FI_SWITCH, ARG, TREE) \ - F(FI_IP_MASK, ARG, ARG) \ - F(FI_PATH_PREPEND, ARG, ARG) \ - F(FI_CLIST_ADD, ARG, ARG) \ - F(FI_CLIST_DEL, ARG, ARG) \ - F(FI_CLIST_FILTER, ARG, ARG) \ - F(FI_ROA_CHECK_IMPLICIT, RTC) \ - F(FI_ROA_CHECK_EXPLICIT, ARG, ARG, RTC) \ - F(FI_FORMAT, ARG) \ - F(FI_ASSERT, ARG, STRING) - -/* The enum itself */ -enum f_instruction_code { -#define F(c, ...) c, -FI__LIST -#undef F - FI__MAX, -} PACKED; +#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) /* Convert the instruction back to the enum name */ const char *f_instruction_name(enum f_instruction_code fi); -struct f_inst; -void f_inst_next(struct f_inst *first, const struct f_inst *append); struct f_inst *f_clear_local_vars(struct f_inst *decls); -#define FIA(x) , FIA_##x -#define FIA_ARG const struct f_inst * -#define FIA_LINE const struct f_inst * -#define FIA_COUNT uint -#define FIA_SYMBOL const struct symbol * -#define FIA_VALI struct f_val -#define FIA_VALP const struct f_val * -#define FIA_FRET enum filter_return -#define FIA_ECS enum ec_subtype -#define FIA_SA struct f_static_attr -#define FIA_EA struct f_dynamic_attr -#define FIA_RTC const struct rtable_config * -#define FIA_TREE const struct f_tree * -#define FIA_STRING const char * -#define F(c, ...) \ - struct f_inst *f_new_inst_##c(enum f_instruction_code MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))()(MACRO_FOREACH(FIA, __VA_ARGS__))); -FI__LIST -#undef F -#undef FIA_ARG -#undef FIA_LINE -#undef FIA_LINEP -#undef FIA_COUNT -#undef FIA_SYMBOL -#undef FIA_VALI -#undef FIA_VALP -#undef FIA_FRET -#undef FIA_ECS -#undef FIA_SA -#undef FIA_EA -#undef FIA_RTC -#undef FIA_STRING -#undef FIA - -#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) - /* Flags for instructions */ enum f_instruction_flags { FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ @@ -202,7 +86,4 @@ struct f_bt_test_suite { const char *dsc; /* Description */ }; -/* Include the auto-generated structures */ -#include "filter/f-inst-struct.h" - #endif diff --git a/filter/f-util.c b/filter/f-util.c index eb948fa0..82aaa385 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -17,22 +17,6 @@ #define P(a,b) ((a<<8) | b) -static const char * const f_instruction_name_str[] = { -#define F(c,...) \ - [c] = #c, -FI__LIST -#undef F -}; - -const char * -f_instruction_name(enum f_instruction_code fi) -{ - if (fi < FI__MAX) - return f_instruction_name_str[fi]; - else - bug("Got unknown instruction code: %d", fi); -} - char * filter_name(struct filter *filter) { @@ -56,18 +40,21 @@ struct filter *f_new_where(const struct f_inst *where) struct f_inst acc = { .fi_code = FI_PRINT_AND_DIE, .lineno = ifs->lino, + .size = 1, .i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, }, }; struct f_inst rej = { .fi_code = FI_PRINT_AND_DIE, .lineno = ifs->lino, + .size = 1, .i_FI_PRINT_AND_DIE = { .fret = F_REJECT, }, }; struct f_inst i = { .fi_code = FI_CONDITION, .lineno = ifs->lino, + .size = 3, .i_FI_CONDITION = { .f1 = where, .f2 = &acc, diff --git a/filter/filter.c b/filter/filter.c index ff702f2b..0cb56fe4 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -48,7 +48,7 @@ #include "conf/conf.h" #include "filter/filter.h" #include "filter/f-inst.h" -#include "filter/f-util.h" +#include "filter/data.h" #define CMP_ERROR 999 @@ -64,6 +64,75 @@ struct filter_state { void (*bt_assert_hook)(int result, const struct f_line_item *assert); +static const char * const f_instruction_name_str[] = { + /* TODO: Make this better */ + [FI_ADD] = "FI_ADD", + [FI_SUBTRACT] = "FI_SUBTRACT", + [FI_MULTIPLY] = "FI_MULTIPLY", + [FI_DIVIDE] = "FI_DIVIDE", + [FI_AND] = "FI_AND", + [FI_OR] = "FI_OR", + [FI_PAIR_CONSTRUCT] = "FI_PAIR_CONSTRUCT", + [FI_EC_CONSTRUCT] = "FI_EC_CONSTRUCT", + [FI_LC_CONSTRUCT] = "FI_LC_CONSTRUCT", + [FI_PATHMASK_CONSTRUCT] = "FI_PATHMASK_CONSTRUCT", + [FI_NEQ] = "FI_NEQ", + [FI_EQ] = "FI_EQ", + [FI_LT] = "FI_LT", + [FI_LTE] = "FI_LTE", + [FI_NOT] = "FI_NOT", + [FI_MATCH] = "FI_MATCH", + [FI_NOT_MATCH] = "FI_NOT_MATCH", + [FI_DEFINED] = "FI_DEFINED", + [FI_TYPE] = "FI_TYPE", + [FI_IS_V4] = "FI_IS_V4", + [FI_SET] = "FI_SET", + [FI_CONSTANT] = "FI_CONSTANT", + [FI_VARIABLE] = "FI_VARIABLE", + [FI_CONSTANT_INDIRECT] = "FI_CONSTANT_INDIRECT", + [FI_PRINT] = "FI_PRINT", + [FI_CONDITION] = "FI_CONDITION", + [FI_PRINT_AND_DIE] = "FI_PRINT_AND_DIE", + [FI_RTA_GET] = "FI_RTA_GET", + [FI_RTA_SET] = "FI_RTA_SET", + [FI_EA_GET] = "FI_EA_GET", + [FI_EA_SET] = "FI_EA_SET", + [FI_EA_UNSET] = "FI_EA_UNSET", + [FI_PREF_GET] = "FI_PREF_GET", + [FI_PREF_SET] = "FI_PREF_SET", + [FI_LENGTH] = "FI_LENGTH", + [FI_SADR_SRC] = "FI_SADR_SRC", + [FI_ROA_MAXLEN] = "FI_ROA_MAXLEN", + [FI_ROA_ASN] = "FI_ROA_ASN", + [FI_IP] = "FI_IP", + [FI_ROUTE_DISTINGUISHER] = "FI_ROUTE_DISTINGUISHER", + [FI_AS_PATH_FIRST] = "FI_AS_PATH_FIRST", + [FI_AS_PATH_LAST] = "FI_AS_PATH_LAST", + [FI_AS_PATH_LAST_NAG] = "FI_AS_PATH_LAST_NAG", + [FI_RETURN] = "FI_RETURN", + [FI_CALL] = "FI_CALL", + [FI_DROP_RESULT] = "FI_DROP_RESULT", + [FI_SWITCH] = "FI_SWITCH", + [FI_IP_MASK] = "FI_IP_MASK", + [FI_PATH_PREPEND] = "FI_PATH_PREPEND", + [FI_CLIST_ADD] = "FI_CLIST_ADD", + [FI_CLIST_DEL] = "FI_CLIST_DEL", + [FI_CLIST_FILTER] = "FI_CLIST_FILTER", + [FI_ROA_CHECK_IMPLICIT] = "FI_ROA_CHECK_IMPLICIT", + [FI_ROA_CHECK_EXPLICIT] = "FI_ROA_CHECK_EXPLICIT", + [FI_FORMAT] = "FI_FORMAT", + [FI_ASSERT] = "FI_ASSERT", +}; + +const char * +f_instruction_name(enum f_instruction_code fi) +{ + if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0]))) + return f_instruction_name_str[fi]; + else + bug("Got unknown instruction code: %d", fi); +} + /* Special undef value for paths and clists */ static inline int undef_value(struct f_val v) @@ -615,18 +684,6 @@ val_format_str(struct filter_state *fs, struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -static uint -inst_line_size(const struct f_inst *what_) -{ - uint cnt = 0; - for ( ; what_; what_ = what_->next) { - switch (what_->fi_code) { -#include "filter/f-inst-line-size.c" - } - } - return cnt; -} - #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) static const char f_dump_line_indent_str[] = " "; @@ -685,7 +742,8 @@ f_postfixify_concat(const struct f_inst * const inst[], uint count) { uint len = 0; for (uint i=0; inext) + len += what->size; struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len); diff --git a/filter/filter_test.c b/filter/filter_test.c index a02f0832..edd73ac8 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -17,7 +17,7 @@ #include "test/bt-utils.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" #include "filter/f-inst.h" #include "conf/conf.h" diff --git a/filter/interpret.m4 b/filter/interpret.m4 index dfd5c6a7..e32b3a76 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -63,10 +63,11 @@ m4_define(TREE, `') m4_define(STRING, `') m4_define(COUNT, `') m4_define(POSTFIXIFY, `') -m4_define(LINE_SIZE, `') m4_define(SAME, `') -m4_define(STRUCT, `') -m4_define(NEW, `') +m4_define(FID_STRUCT_IN, `m4_divert(-1)') +m4_define(FID_NEW_ARGS, `m4_divert(-1)') +m4_define(FID_NEW_BODY, `m4_divert(-1)') +m4_define(FID_END, `m4_divert(2)') m4_m4wrap(` INST_FLUSH() diff --git a/filter/line-size.m4 b/filter/line-size.m4 deleted file mode 100644 index 051d3b90..00000000 --- a/filter/line-size.m4 +++ /dev/null @@ -1,41 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Line size counting -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -case INST_NAME(): -cnt += 1; -#define what ((const struct f_inst_]]INST_NAME()[[ *) &(what_->i_]]INST_NAME()[[)) -m4_undivert(2) -#undef what -break; -m4_divert(-1) -]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(ARG, `m4_divert(2)cnt += inst_line_size(what->f$1); -m4_divert(-1)') -m4_define(ARG_T, `m4_divert(2)cnt += inst_line_size(what->f$1); -m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(2)cnt += inst_line_size(what->f$1); -m4_divert(-1)') -m4_define(LINE_SIZE, `m4_divert(2)$1m4_divert(-1)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) - -default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); -') - -m4_changequote([[,]]) diff --git a/filter/new.m4 b/filter/new.m4 deleted file mode 100644 index 38295e5c..00000000 --- a/filter/new.m4 +++ /dev/null @@ -1,78 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Construction of per-instruction structures -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# -# -# Diversions: -# 1 for prepared output -# 2 for function arguments -# 3 for function body - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(FNSTOP, `m4_divert(-1)') -m4_define(FNOUT, `m4_divert(1)') -m4_define(FNARG, `m4_divert(2)') -m4_define(FNBODY, `m4_divert(3)') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -FNOUT()DNL -struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(2) -) { - struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); - what->fi_code = fi_code; - what->lineno = ifs->lino; -m4_undivert(3) - return what; -} -FNSTOP() -]]DNL -)') - -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(WHAT, `what->i_[[]]INST_NAME()') - -m4_define(FNMETAARG, `FNARG(), $1 $2 -FNBODY() WHAT().$2 = $2; -FNSTOP()') -m4_define(ARG, `FNMETAARG(const struct f_inst *, f$1)') -m4_define(ARG_ANY, `FNMETAARG(const struct f_inst *, f$1)') -m4_define(LINE, `FNMETAARG(const struct f_inst *, f$1)') -m4_define(SYMBOL, `FNMETAARG(const struct symbol *, sym)') -m4_define(VALI, `FNMETAARG(struct f_val, vali)') -m4_define(VALP, `FNMETAARG(const struct f_val *, valp)') -m4_define(VAR, `FNARG(), const struct symbol * sym -FNBODY() WHAT().valp = (WHAT().sym = sym)->def; -FNSTOP()') -m4_define(FRET, `FNMETAARG(enum filter_return, fret)') -m4_define(ECS, `FNMETAARG(enum ec_subtype, ecs)') -m4_define(RTC, `FNMETAARG(const struct rtable_config *, rtc)') -m4_define(STATIC_ATTR, `FNMETAARG(struct f_static_attr, sa)') -m4_define(DYNAMIC_ATTR, `FNMETAARG(struct f_dynamic_attr, da)') -m4_define(COUNT, `FNMETAARG(uint, count)') -m4_define(TREE, `FNMETAARG(const struct f_tree *, tree)') -m4_define(STRING, `FNMETAARG(const char *, s)') -m4_define(NEW, `FNARG()$1 -FNBODY()$2 -FNSTOP()') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0) -#include "nest/bird.h" -#include "conf/conf.h" -#include "filter/filter.h" -#include "filter/f-inst.h" - -m4_undivert(1) - -') - -m4_changequote([[,]]) diff --git a/filter/struct.m4 b/filter/struct.m4 deleted file mode 100644 index 7af28cfd..00000000 --- a/filter/struct.m4 +++ /dev/null @@ -1,73 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Definition of per-instruction structures -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -struct f_inst_[[]]INST_NAME() { -m4_undivert(2) -}; -m4_divert(3) -struct f_inst_[[]]INST_NAME() i_[[]]INST_NAME(); -m4_divert(-1) -]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(ARG, `m4_divert(2)const struct f_inst *f$1; -m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(2)const struct f_inst *f$1; -m4_divert(-1)') -m4_define(LINE, `m4_divert(2)const struct f_inst *f$1; -m4_divert(-1)') -m4_define(LINEP, `m4_divert(2)const struct f_line *fl$1; -m4_divert(-1)') -m4_define(SYMBOL, `m4_divert(2)const struct symbol *sym; -m4_divert(-1)') -m4_define(VALI, `m4_divert(2)struct f_val vali; -m4_divert(-1)') -m4_define(VALP, `m4_divert(2)const struct f_val *valp; -m4_divert(-1)') -m4_define(VAR, `VALP()SYMBOL()') -m4_define(FRET, `m4_divert(2)enum filter_return fret; -m4_divert(-1)') -m4_define(ECS, `m4_divert(2)enum ec_subtype ecs; -m4_divert(-1)') -m4_define(RTC, `m4_divert(2)const struct rtable_config *rtc; -m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(2)struct f_static_attr sa; -m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(2)struct f_dynamic_attr da; -m4_divert(-1)') -m4_define(COUNT, `m4_divert(2)uint count; -m4_divert(-1)') -m4_define(TREE, `m4_divert(2)const struct f_tree *tree; -m4_divert(-1)') -m4_define(STRING, `m4_divert(2)const char *s; -m4_divert(-1)') -m4_define(STRUCT, `m4_divert(2)$1 -m4_divert(-1)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) - -struct f_inst { - const struct f_inst *next; /* Next instruction */ - enum f_instruction_code fi_code; /* Instruction code */ - int lineno; /* Line number */ - union { - m4_undivert(3) - }; -}; -') - -m4_changequote([[,]]) diff --git a/filter/tree.c b/filter/tree.c index 879b0859..46d6e529 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -10,7 +10,7 @@ #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" /** * find_tree diff --git a/filter/tree_test.c b/filter/tree_test.c index 9e0de50f..6472d17e 100644 --- a/filter/tree_test.c +++ b/filter/tree_test.c @@ -10,7 +10,7 @@ #include "test/bt-utils.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" #include "conf/conf.h" #define MAX_TREE_HEIGHT 13 diff --git a/filter/trie.c b/filter/trie.c index dccf9130..3038f5ec 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -73,7 +73,7 @@ #include "lib/string.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" /* diff --git a/filter/trie_test.c b/filter/trie_test.c index b6959c4a..38c387b0 100644 --- a/filter/trie_test.c +++ b/filter/trie_test.c @@ -10,7 +10,7 @@ #include "test/bt-utils.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" #include "conf/conf.h" #define TESTS_NUM 10 diff --git a/nest/a-path.c b/nest/a-path.c index ac13d0fa..62369af3 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -13,7 +13,7 @@ #include "lib/resource.h" #include "lib/unaligned.h" #include "lib/string.h" -#include "filter/f-util.h" +#include "filter/data.h" // static inline void put_as(byte *data, u32 as) { put_u32(data, as); } // static inline u32 get_as(byte *data) { return get_u32(data); } diff --git a/nest/cmds.c b/nest/cmds.c index 40d397cc..2b83033f 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -15,7 +15,7 @@ #include "lib/string.h" #include "lib/resource.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" extern int shutting_down; extern int configuring; diff --git a/nest/rt-table.c b/nest/rt-table.c index d72a8695..6c8e662e 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -39,7 +39,7 @@ #include "lib/string.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" #include "lib/hash.h" #include "lib/string.h" #include "lib/alloca.h" diff --git a/proto/static/config.Y b/proto/static/config.Y index 0e53c978..3e9ac578 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -139,7 +139,7 @@ stat_route: stat_route_item: cmd { if (this_srt_last_cmd) - f_inst_next(this_srt_last_cmd, $1); + this_srt_last_cmd->next = $1; else this_srt_cmds = $1; this_srt_last_cmd = $1; diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index f9002d58..0fdd5b34 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -36,7 +36,7 @@ #include "nest/locks.h" #include "conf/conf.h" #include "filter/filter.h" -#include "filter/f-util.h" +#include "filter/data.h" #include "unix.h" #include "krt.h" From 75206f266f8534367b88401be463953b7d5dc770 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 11 Feb 2019 15:27:47 +0100 Subject: [PATCH 24/88] Conf: Fixed makefiles --- Makefile.in | 3 +++ client/Makefile | 1 + client/{cmds.m4 => cmds.Y} | 0 conf/Makefile | 10 +++++----- filter/Makefile | 2 ++ 5 files changed, 11 insertions(+), 5 deletions(-) rename client/{cmds.m4 => cmds.Y} (100%) diff --git a/Makefile.in b/Makefile.in index 0ecd6811..695fa744 100644 --- a/Makefile.in +++ b/Makefile.in @@ -76,6 +76,8 @@ $(daemon): LIBS += $(DAEMON_LIBS) # Include directories dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@ +# conf/Makefile declarations needed for all other modules +conf-lex-targets := $(addprefix $(objdir)/conf/,cf-lex.o) conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) cf-local = $(conf-y-targets): $(s)config.Y @@ -99,6 +101,7 @@ endef clean = $(eval $(call clean_in,$(1))) +# Include main Makefiles of the directories include $(addsuffix /Makefile,$(addprefix $(srcdir)/,$(dirs))) # Generic rules diff --git a/client/Makefile b/client/Makefile index fccb8346..c91a30e0 100644 --- a/client/Makefile +++ b/client/Makefile @@ -2,6 +2,7 @@ src := commands.c util.c client.c obj := $(src-o-files) $(all-client) +$(conf-y-targets): $(s)cmds.Y $(o)commands.o: $(objdir)/conf/commands.h diff --git a/client/cmds.m4 b/client/cmds.Y similarity index 100% rename from client/cmds.m4 rename to client/cmds.Y diff --git a/conf/Makefile b/conf/Makefile index 39628bff..be823d40 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -10,12 +10,12 @@ BISON_DEBUG=-t #FLEX_DEBUG=-d endif -$(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y - $(M4) $(M4FLAGS) -P $| $^ >$@ +$(o)cf-parse.y: $(s)gen_parser.m4 +$(o)keywords.h: $(s)gen_keywords.m4 +$(o)commands.h: $(s)gen_commands.m4 -$(o)cf-parse.y: | $(s)gen_parser.m4 -$(o)keywords.h: | $(s)gen_keywords.m4 -$(o)commands.h: | $(s)gen_commands.m4 $(srcdir)/client/cmds.m4 +$(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y + $(M4) $(M4FLAGS) -P $(if $(word 2,$(filter %.m4,$^)),$(error "Too many M4 scripts for one target"),$(filter %.m4,$^)) $(filter %.Y,$^) >$@ $(o)cf-parse.tab.h: $(o)cf-parse.tab.c diff --git a/filter/Makefile b/filter/Makefile index f5f50045..18fd8137 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -3,6 +3,8 @@ obj := $(src-o-files) $(all-daemon) $(cf-local) +$(conf-y-targets) $(conf-lex-targets): $(o)f-inst-decl.h + M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) $(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp From 87bd7cd7b03f24c9d7c37a2a060ef553f26ead29 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 11 Feb 2019 16:44:14 +0100 Subject: [PATCH 25/88] Filter: split the constructors to a separate file --- filter/Makefile | 13 ++++++++----- filter/decl.m4 | 21 ++++++++++++++++++--- filter/f-inst.h | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/filter/Makefile b/filter/Makefile index 18fd8137..78d39638 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,9 +1,9 @@ -src := filter.c f-util.c tree.c trie.c +src := filter.c f-util.c tree.c trie.c inst-gen.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(conf-y-targets) $(conf-lex-targets): $(o)f-inst-decl.h +$(conf-y-targets) $(conf-lex-targets) $(src-o-files): $(o)inst-gen.h M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) @@ -16,13 +16,16 @@ $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)f-inst-decl.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ +$(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -DTARGET=H -P $^ >$@ + +$(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@ $(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)f-inst-decl.h +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)inst-gen.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/decl.m4 b/filter/decl.m4 index bdbb3e27..7ff22c2e 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -19,9 +19,10 @@ m4_divert(-1)m4_dnl # 13 constructor body # Flush the completed instruction - m4_define(FID_END, `m4_divert(-1)') +m4_dnl m4_debugmode(aceflqtx) + m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') m4_define(FID_STRUCT, `FID_ZONE(1, Per-instruction structure)') m4_define(FID_UNION, `FID_ZONE(2, Union member)') @@ -32,6 +33,11 @@ m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') +m4_define(FID_ALL, `/* fidall */m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') +m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') +m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') + + m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ FID_ENUM INST_NAME(), @@ -42,9 +48,11 @@ m4_undivert(101) FID_UNION struct f_inst_[[]]INST_NAME() i_[[]]INST_NAME(); FID_NEW -static inline struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code m4_undivert(102) -) { +) +FID_H ; FID_C +{ struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); what_->fi_code = fi_code; what_->lineno = ifs->lino; @@ -53,6 +61,7 @@ m4_undivert(102) m4_undivert(103) return what_; } +FID_ALL FID_END ]])') @@ -103,6 +112,11 @@ m4_define(STRING, `FID_MEMBER(const char *, s)') m4_m4wrap(` INST_FLUSH() m4_divert(0) +FID_C +#include "nest/bird.h" +#include "filter/filter.h" +#include "filter/f-inst.h" +FID_H /* Filter instruction codes */ enum f_instruction_code { m4_undivert(4) @@ -121,6 +135,7 @@ struct f_inst { }; }; +FID_ALL /* Instruction constructors */ m4_undivert(3) ') diff --git a/filter/f-inst.h b/filter/f-inst.h index 1423e685..ad994857 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -16,7 +16,7 @@ #include "filter/data.h" /* Include generated filter instruction declarations */ -#include "filter/f-inst-decl.h" +#include "filter/inst-gen.h" #define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) From 5289304519918f62d099463123bf6c69a0dd497e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 11 Feb 2019 17:12:48 +0100 Subject: [PATCH 26/88] Filter data manipulation functions separated to their file --- filter/Makefile | 2 +- filter/data.c | 519 ++++++++++++++++++++++++++++++++++++++ filter/data.h | 33 +++ filter/f-inst.c | 8 +- filter/filter.c | 642 +----------------------------------------------- filter/filter.h | 6 +- nest/cmds.c | 11 +- 7 files changed, 572 insertions(+), 649 deletions(-) create mode 100644 filter/data.c diff --git a/filter/Makefile b/filter/Makefile index 78d39638..df7ff3f9 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,4 +1,4 @@ -src := filter.c f-util.c tree.c trie.c inst-gen.c +src := filter.c data.c f-util.c tree.c trie.c inst-gen.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/filter/data.c b/filter/data.c new file mode 100644 index 00000000..b389b8e8 --- /dev/null +++ b/filter/data.c @@ -0,0 +1,519 @@ +/* + * Filters: utility functions + * + * (c) 1998 Pavel Machek + * (c) 2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + * + */ + +#include "nest/bird.h" +#include "lib/lists.h" +#include "lib/resource.h" +#include "lib/socket.h" +#include "lib/string.h" +#include "lib/unaligned.h" +#include "lib/net.h" +#include "lib/ip.h" +#include "nest/route.h" +#include "nest/protocol.h" +#include "nest/iface.h" +#include "nest/attrs.h" +#include "conf/conf.h" +#include "filter/filter.h" +#include "filter/f-inst.h" +#include "filter/data.h" + +const struct f_val f_const_empty_path = { + .type = T_PATH, + .val.ad = &null_adata, +}, f_const_empty_clist = { + .type = T_CLIST, + .val.ad = &null_adata, +}, f_const_empty_eclist = { + .type = T_ECLIST, + .val.ad = &null_adata, +}, f_const_empty_lclist = { + .type = T_LCLIST, + .val.ad = &null_adata, +}; + +static struct adata * +adata_empty(struct linpool *pool, int l) +{ + struct adata *res = lp_alloc(pool, sizeof(struct adata) + l); + res->length = l; + return res; +} + +static void +pm_format(const struct f_path_mask *p, buffer *buf) +{ + buffer_puts(buf, "[= "); + + for (uint i=0; ilen; i++) + { + switch(p->item[i].kind) + { + case PM_ASN: + buffer_print(buf, "%u ", p->item[i].asn); + break; + + case PM_QUESTION: + buffer_puts(buf, "? "); + break; + + case PM_ASTERISK: + buffer_puts(buf, "* "); + break; + + case PM_ASN_RANGE: + buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to); + break; + + case PM_ASN_EXPR: + ASSERT(0); + } + + } + + buffer_puts(buf, "=]"); +} + +static inline int +lcomm_cmp(lcomm v1, lcomm v2) +{ + if (v1.asn != v2.asn) + return (v1.asn > v2.asn) ? 1 : -1; + if (v1.ldp1 != v2.ldp1) + return (v1.ldp1 > v2.ldp1) ? 1 : -1; + if (v1.ldp2 != v2.ldp2) + return (v1.ldp2 > v2.ldp2) ? 1 : -1; + return 0; +} + +/** + * val_compare - compare two values + * @v1: first value + * @v2: second value + * + * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on + * error. Tree module relies on this giving consistent results so + * that it can be used for building balanced trees. + */ +int +val_compare(const struct f_val *v1, const struct f_val *v2) +{ + if (v1->type != v2->type) { + if (v1->type == T_VOID) /* Hack for else */ + return -1; + if (v2->type == T_VOID) + return 1; + + /* IP->Quad implicit conversion */ + if ((v1->type == T_QUAD) && val_is_ip4(v2)) + return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip)); + if (val_is_ip4(v1) && (v2->type == T_QUAD)) + return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i); + + debug( "Types do not match in val_compare\n" ); + return F_CMP_ERROR; + } + + switch (v1->type) { + case T_VOID: + return 0; + case T_ENUM: + case T_INT: + case T_BOOL: + case T_PAIR: + case T_QUAD: + return uint_cmp(v1->val.i, v2->val.i); + case T_EC: + case T_RD: + return u64_cmp(v1->val.ec, v2->val.ec); + case T_LC: + return lcomm_cmp(v1->val.lc, v2->val.lc); + case T_IP: + return ipa_compare(v1->val.ip, v2->val.ip); + case T_NET: + return net_compare(v1->val.net, v2->val.net); + case T_STRING: + return strcmp(v1->val.s, v2->val.s); + default: + return F_CMP_ERROR; + } +} + +static int +pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2) +{ + if (m1->len != m2->len) + + for (uint i=0; ilen; i++) + { + if (m1->item[i].kind != m2->item[i].kind) + return 0; + + switch (m1->item[i].kind) { + case PM_ASN: + if (m1->item[i].asn != m2->item[i].asn) + return 0; + break; + case PM_ASN_EXPR: + if (!f_same(m1->item[i].expr, m2->item[i].expr)) + return 0; + break; + case PM_ASN_RANGE: + if (m1->item[i].from != m2->item[i].from) + return 0; + if (m1->item[i].to != m2->item[i].to) + return 0; + break; + } + } + + return 1; +} + +/** + * val_same - compare two values + * @v1: first value + * @v2: second value + * + * Compares two values and returns 1 if they are same and 0 if not. + * Comparison of values of different types is valid and returns 0. + */ +int +val_same(const struct f_val *v1, const struct f_val *v2) +{ + int rc; + + rc = val_compare(v1, v2); + if (rc != F_CMP_ERROR) + return !rc; + + if (v1->type != v2->type) + return 0; + + switch (v1->type) { + case T_PATH_MASK: + return pm_same(v1->val.path_mask, v2->val.path_mask); + case T_PATH: + case T_CLIST: + case T_ECLIST: + case T_LCLIST: + return adata_same(v1->val.ad, v2->val.ad); + case T_SET: + return same_tree(v1->val.t, v2->val.t); + case T_PREFIX_SET: + return trie_same(v1->val.ti, v2->val.ti); + default: + bug("Invalid type in val_same(): %x", v1->type); + } +} + +int +clist_set_type(const struct f_tree *set, struct f_val *v) +{ + switch (set->from.type) + { + case T_PAIR: + v->type = T_PAIR; + return 1; + + case T_QUAD: + v->type = T_QUAD; + return 1; + + case T_IP: + if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to))) + { + v->type = T_QUAD; + return 1; + } + /* Fall through */ + default: + v->type = T_VOID; + return 0; + } +} + +static int +clist_match_set(const struct adata *clist, const struct f_tree *set) +{ + if (!clist) + return 0; + + struct f_val v; + if (!clist_set_type(set, &v)) + return F_CMP_ERROR; + + u32 *l = (u32 *) clist->data; + u32 *end = l + clist->length/4; + + while (l < end) { + v.val.i = *l++; + if (find_tree(set, &v)) + return 1; + } + return 0; +} + +static int +eclist_match_set(const struct adata *list, const struct f_tree *set) +{ + if (!list) + return 0; + + if (!eclist_set_type(set)) + return F_CMP_ERROR; + + struct f_val v; + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + v.type = T_EC; + for (i = 0; i < len; i += 2) { + v.val.ec = ec_get(l, i); + if (find_tree(set, &v)) + return 1; + } + + return 0; +} + +static int +lclist_match_set(const struct adata *list, const struct f_tree *set) +{ + if (!list) + return 0; + + if (!lclist_set_type(set)) + return F_CMP_ERROR; + + struct f_val v; + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + v.type = T_LC; + for (i = 0; i < len; i += 3) { + v.val.lc = lc_get(l, i); + if (find_tree(set, &v)) + return 1; + } + + return 0; +} + +const struct adata * +clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) +{ + if (!list) + return NULL; + + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + struct f_val v; + if (tree) + clist_set_type(set->val.t, &v); + else + v.type = T_PAIR; + + int len = int_set_get_size(list); + u32 *l = int_set_get_data(list); + u32 tmp[len]; + u32 *k = tmp; + u32 *end = l + len; + + while (l < end) { + v.val.i = *l++; + /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ + if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos) + *k++ = v.val.i; + } + + uint nl = (k - tmp) * sizeof(u32); + if (nl == list->length) + return list; + + struct adata *res = adata_empty(pool, nl); + memcpy(res->data, tmp, nl); + return res; +} + +const struct adata * +eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) +{ + if (!list) + return NULL; + + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + struct f_val v; + + int len = int_set_get_size(list); + u32 *l = int_set_get_data(list); + u32 tmp[len]; + u32 *k = tmp; + int i; + + v.type = T_EC; + for (i = 0; i < len; i += 2) { + v.val.ec = ec_get(l, i); + /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ + if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) { + *k++ = l[i]; + *k++ = l[i+1]; + } + } + + uint nl = (k - tmp) * sizeof(u32); + if (nl == list->length) + return list; + + struct adata *res = adata_empty(pool, nl); + memcpy(res->data, tmp, nl); + return res; +} + +const struct adata * +lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) +{ + if (!list) + return NULL; + + int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ + struct f_val v; + + int len = int_set_get_size(list); + u32 *l = int_set_get_data(list); + u32 tmp[len]; + u32 *k = tmp; + int i; + + v.type = T_LC; + for (i = 0; i < len; i += 3) { + v.val.lc = lc_get(l, i); + /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ + if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos) + k = lc_copy(k, l+i); + } + + uint nl = (k - tmp) * sizeof(u32); + if (nl == list->length) + return list; + + struct adata *res = adata_empty(pool, nl); + memcpy(res->data, tmp, nl); + return res; +} + +/** + * val_in_range - implement |~| operator + * @v1: element + * @v2: set + * + * Checks if @v1 is element (|~| operator) of @v2. + */ +int +val_in_range(const struct f_val *v1, const struct f_val *v2) +{ + if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK)) + return as_path_match(v1->val.ad, v2->val.path_mask); + + if ((v1->type == T_INT) && (v2->type == T_PATH)) + return as_path_contains(v2->val.ad, v1->val.i, 1); + + if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST)) + return int_set_contains(v2->val.ad, v1->val.i); + /* IP->Quad implicit conversion */ + 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); + + if ((v1->type == T_LC) && (v2->type == T_LCLIST)) + return lc_set_contains(v2->val.ad, v1->val.lc); + + if ((v1->type == T_STRING) && (v2->type == T_STRING)) + return patmatch(v2->val.s, v1->val.s); + + if ((v1->type == T_IP) && (v2->type == T_NET)) + return ipa_in_netX(v1->val.ip, v2->val.net); + + if ((v1->type == T_NET) && (v2->type == T_NET)) + return net_in_netX(v1->val.net, v2->val.net); + + if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET)) + return trie_match_net(v2->val.ti, v1->val.net); + + if (v2->type != T_SET) + return F_CMP_ERROR; + + /* With integrated Quad<->IP implicit conversion */ + if ((v1->type == v2->val.t->from.type) || + ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to)))) + return !!find_tree(v2->val.t, v1); + + if (v1->type == T_CLIST) + return clist_match_set(v1->val.ad, v2->val.t); + + if (v1->type == T_ECLIST) + return eclist_match_set(v1->val.ad, v2->val.t); + + if (v1->type == T_LCLIST) + return lclist_match_set(v1->val.ad, v2->val.t); + + if (v1->type == T_PATH) + return as_path_match_set(v1->val.ad, v2->val.t); + + return F_CMP_ERROR; +} + +/* + * val_format - format filter value + */ +void +val_format(const struct f_val *v, buffer *buf) +{ + char buf2[1024]; + switch (v->type) + { + case T_VOID: buffer_puts(buf, "(void)"); return; + case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return; + case T_INT: buffer_print(buf, "%u", v->val.i); return; + case T_STRING: buffer_print(buf, "%s", v->val.s); return; + case T_IP: buffer_print(buf, "%I", v->val.ip); return; + case T_NET: buffer_print(buf, "%N", v->val.net); return; + case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return; + case T_QUAD: buffer_print(buf, "%R", v->val.i); return; + case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return; + case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return; + case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return; + case T_PREFIX_SET: trie_format(v->val.ti, buf); return; + case T_SET: tree_format(v->val.t, buf); return; + case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return; + case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; + case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; + case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; + case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return; + case T_PATH_MASK: pm_format(v->val.path_mask, buf); return; + default: buffer_print(buf, "[unknown type %x]", v->type); return; + } +} + +static char val_dump_buffer[1024]; +const char * +val_dump(const struct f_val *v) { + static buffer b = { + .start = val_dump_buffer, + .end = val_dump_buffer + 1024, + }; + b.pos = b.start; + val_format(v, &b); + return val_dump_buffer; +} + diff --git a/filter/data.h b/filter/data.h index 58db3e44..6ef2024f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -164,6 +164,39 @@ int trie_match_net(const struct f_trie *t, const net_addr *n); int trie_same(const struct f_trie *t1, const struct f_trie *t2); void trie_format(const struct f_trie *t, buffer *buf); +#define F_CMP_ERROR 999 + +int val_same(const struct f_val *v1, const struct f_val *v2); +int val_compare(const struct f_val *v1, const struct f_val *v2); +void val_format(const struct f_val *v, buffer *buf); +const char *val_dump(const struct f_val *v); + +static inline int val_is_ip4(const struct f_val *v) +{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); } +int val_in_range(const struct f_val *v1, const struct f_val *v2); + +int clist_set_type(const struct f_tree *set, struct f_val *v); +static inline int eclist_set_type(const struct f_tree *set) +{ return set->from.type == T_EC; } +static inline int lclist_set_type(const struct f_tree *set) +{ return set->from.type == T_LC; } + +const struct adata *clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); +const struct adata *eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); +const struct adata *lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); + + +/* 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 == &null_adata); +} + extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; +enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); + #endif diff --git a/filter/f-inst.c b/filter/f-inst.c index afb895c5..96d6108c 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -165,7 +165,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_compare(&v1, &v2); - if (i == CMP_ERROR) + if (i == F_CMP_ERROR) runtime( "Can't compare values of incompatible types" ); RESULT(T_BOOL, i, (i == -1)); } @@ -174,7 +174,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_compare(&v1, &v2); - if (i == CMP_ERROR) + if (i == F_CMP_ERROR) runtime( "Can't compare values of incompatible types" ); RESULT(T_BOOL, i, (i != 1)); } @@ -188,7 +188,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_in_range(&v1, &v2); - if (i == CMP_ERROR) + if (i == F_CMP_ERROR) runtime( "~ applied on unknown type pair" ); RESULT(T_BOOL, i, !!i); } @@ -197,7 +197,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_in_range(&v1, &v2); - if (res.val.i == CMP_ERROR) + if (res.val.i == F_CMP_ERROR) runtime( "!~ applied on unknown type pair" ); RESULT(T_BOOL, i, !i); } diff --git a/filter/filter.c b/filter/filter.c index 0cb56fe4..0bcf9836 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -50,8 +50,6 @@ #include "filter/f-inst.h" #include "filter/data.h" -#define CMP_ERROR 999 - /* Internal filter state, to be allocated on stack when executing filters */ struct filter_state { struct rte **rte; @@ -133,507 +131,6 @@ f_instruction_name(enum f_instruction_code fi) bug("Got unknown instruction code: %d", fi); } -/* 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 == &null_adata); -} - -const struct f_val f_const_empty_path = { - .type = T_PATH, - .val.ad = &null_adata, -}, f_const_empty_clist = { - .type = T_CLIST, - .val.ad = &null_adata, -}, f_const_empty_eclist = { - .type = T_ECLIST, - .val.ad = &null_adata, -}, f_const_empty_lclist = { - .type = T_LCLIST, - .val.ad = &null_adata, -}; - -static struct adata * -adata_empty(struct linpool *pool, int l) -{ - struct adata *res = lp_alloc(pool, sizeof(struct adata) + l); - res->length = l; - return res; -} - -static void -pm_format(const struct f_path_mask *p, buffer *buf) -{ - buffer_puts(buf, "[= "); - - for (uint i=0; ilen; i++) - { - switch(p->item[i].kind) - { - case PM_ASN: - buffer_print(buf, "%u ", p->item[i].asn); - break; - - case PM_QUESTION: - buffer_puts(buf, "? "); - break; - - case PM_ASTERISK: - buffer_puts(buf, "* "); - break; - - case PM_ASN_RANGE: - buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to); - break; - - case PM_ASN_EXPR: - ASSERT(0); - } - - } - - buffer_puts(buf, "=]"); -} - -static inline int val_is_ip4(const struct f_val *v) -{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); } - -static inline int -lcomm_cmp(lcomm v1, lcomm v2) -{ - if (v1.asn != v2.asn) - return (v1.asn > v2.asn) ? 1 : -1; - if (v1.ldp1 != v2.ldp1) - return (v1.ldp1 > v2.ldp1) ? 1 : -1; - if (v1.ldp2 != v2.ldp2) - return (v1.ldp2 > v2.ldp2) ? 1 : -1; - return 0; -} - -/** - * val_compare - compare two values - * @v1: first value - * @v2: second value - * - * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on - * error. Tree module relies on this giving consistent results so - * that it can be used for building balanced trees. - */ -int -val_compare(const struct f_val *v1, const struct f_val *v2) -{ - if (v1->type != v2->type) { - if (v1->type == T_VOID) /* Hack for else */ - return -1; - if (v2->type == T_VOID) - return 1; - - /* IP->Quad implicit conversion */ - if ((v1->type == T_QUAD) && val_is_ip4(v2)) - return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip)); - if (val_is_ip4(v1) && (v2->type == T_QUAD)) - return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i); - - debug( "Types do not match in val_compare\n" ); - return CMP_ERROR; - } - - switch (v1->type) { - case T_VOID: - return 0; - case T_ENUM: - case T_INT: - case T_BOOL: - case T_PAIR: - case T_QUAD: - return uint_cmp(v1->val.i, v2->val.i); - case T_EC: - case T_RD: - return u64_cmp(v1->val.ec, v2->val.ec); - case T_LC: - return lcomm_cmp(v1->val.lc, v2->val.lc); - case T_IP: - return ipa_compare(v1->val.ip, v2->val.ip); - case T_NET: - return net_compare(v1->val.net, v2->val.net); - case T_STRING: - return strcmp(v1->val.s, v2->val.s); - default: - return CMP_ERROR; - } -} - -static int -pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2) -{ - if (m1->len != m2->len) - - for (uint i=0; ilen; i++) - { - if (m1->item[i].kind != m2->item[i].kind) - return 0; - - switch (m1->item[i].kind) { - case PM_ASN: - if (m1->item[i].asn != m2->item[i].asn) - return 0; - break; - case PM_ASN_EXPR: - if (!f_same(m1->item[i].expr, m2->item[i].expr)) - return 0; - break; - case PM_ASN_RANGE: - if (m1->item[i].from != m2->item[i].from) - return 0; - if (m1->item[i].to != m2->item[i].to) - return 0; - break; - } - } - - return 1; -} - -/** - * val_same - compare two values - * @v1: first value - * @v2: second value - * - * Compares two values and returns 1 if they are same and 0 if not. - * Comparison of values of different types is valid and returns 0. - */ -int -val_same(const struct f_val *v1, const struct f_val *v2) -{ - int rc; - - rc = val_compare(v1, v2); - if (rc != CMP_ERROR) - return !rc; - - if (v1->type != v2->type) - return 0; - - switch (v1->type) { - case T_PATH_MASK: - return pm_same(v1->val.path_mask, v2->val.path_mask); - case T_PATH: - case T_CLIST: - case T_ECLIST: - case T_LCLIST: - return adata_same(v1->val.ad, v2->val.ad); - case T_SET: - return same_tree(v1->val.t, v2->val.t); - case T_PREFIX_SET: - return trie_same(v1->val.ti, v2->val.ti); - default: - bug("Invalid type in val_same(): %x", v1->type); - } -} - -static int -clist_set_type(const struct f_tree *set, struct f_val *v) -{ - switch (set->from.type) - { - case T_PAIR: - v->type = T_PAIR; - return 1; - - case T_QUAD: - v->type = T_QUAD; - return 1; - - case T_IP: - if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to))) - { - v->type = T_QUAD; - return 1; - } - /* Fall through */ - default: - v->type = T_VOID; - return 0; - } -} - -static inline int -eclist_set_type(const struct f_tree *set) -{ return set->from.type == T_EC; } - -static inline int -lclist_set_type(const struct f_tree *set) -{ return set->from.type == T_LC; } - -static int -clist_match_set(const struct adata *clist, const struct f_tree *set) -{ - if (!clist) - return 0; - - struct f_val v; - if (!clist_set_type(set, &v)) - return CMP_ERROR; - - u32 *l = (u32 *) clist->data; - u32 *end = l + clist->length/4; - - while (l < end) { - v.val.i = *l++; - if (find_tree(set, &v)) - return 1; - } - return 0; -} - -static int -eclist_match_set(const struct adata *list, const struct f_tree *set) -{ - if (!list) - return 0; - - if (!eclist_set_type(set)) - return CMP_ERROR; - - struct f_val v; - u32 *l = int_set_get_data(list); - int len = int_set_get_size(list); - int i; - - v.type = T_EC; - for (i = 0; i < len; i += 2) { - v.val.ec = ec_get(l, i); - if (find_tree(set, &v)) - return 1; - } - - return 0; -} - -static int -lclist_match_set(const struct adata *list, const struct f_tree *set) -{ - if (!list) - return 0; - - if (!lclist_set_type(set)) - return CMP_ERROR; - - struct f_val v; - u32 *l = int_set_get_data(list); - int len = int_set_get_size(list); - int i; - - v.type = T_LC; - for (i = 0; i < len; i += 3) { - v.val.lc = lc_get(l, i); - if (find_tree(set, &v)) - return 1; - } - - return 0; -} - -static const struct adata * -clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) -{ - if (!list) - return NULL; - - int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ - struct f_val v; - if (tree) - clist_set_type(set->val.t, &v); - else - v.type = T_PAIR; - - int len = int_set_get_size(list); - u32 *l = int_set_get_data(list); - u32 tmp[len]; - u32 *k = tmp; - u32 *end = l + len; - - while (l < end) { - v.val.i = *l++; - /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos) - *k++ = v.val.i; - } - - uint nl = (k - tmp) * sizeof(u32); - if (nl == list->length) - return list; - - struct adata *res = adata_empty(pool, nl); - memcpy(res->data, tmp, nl); - return res; -} - -static const struct adata * -eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) -{ - if (!list) - return NULL; - - int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ - struct f_val v; - - int len = int_set_get_size(list); - u32 *l = int_set_get_data(list); - u32 tmp[len]; - u32 *k = tmp; - int i; - - v.type = T_EC; - for (i = 0; i < len; i += 2) { - v.val.ec = ec_get(l, i); - /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) { - *k++ = l[i]; - *k++ = l[i+1]; - } - } - - uint nl = (k - tmp) * sizeof(u32); - if (nl == list->length) - return list; - - struct adata *res = adata_empty(pool, nl); - memcpy(res->data, tmp, nl); - return res; -} - -static const struct adata * -lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos) -{ - if (!list) - return NULL; - - int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ - struct f_val v; - - int len = int_set_get_size(list); - u32 *l = int_set_get_data(list); - u32 tmp[len]; - u32 *k = tmp; - int i; - - v.type = T_LC; - for (i = 0; i < len; i += 3) { - v.val.lc = lc_get(l, i); - /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */ - if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos) - k = lc_copy(k, l+i); - } - - uint nl = (k - tmp) * sizeof(u32); - if (nl == list->length) - return list; - - struct adata *res = adata_empty(pool, nl); - memcpy(res->data, tmp, nl); - return res; -} - -/** - * val_in_range - implement |~| operator - * @v1: element - * @v2: set - * - * Checks if @v1 is element (|~| operator) of @v2. - */ -static int -val_in_range(const struct f_val *v1, const struct f_val *v2) -{ - if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK)) - return as_path_match(v1->val.ad, v2->val.path_mask); - - if ((v1->type == T_INT) && (v2->type == T_PATH)) - return as_path_contains(v2->val.ad, v1->val.i, 1); - - if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST)) - return int_set_contains(v2->val.ad, v1->val.i); - /* IP->Quad implicit conversion */ - 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); - - if ((v1->type == T_LC) && (v2->type == T_LCLIST)) - return lc_set_contains(v2->val.ad, v1->val.lc); - - if ((v1->type == T_STRING) && (v2->type == T_STRING)) - return patmatch(v2->val.s, v1->val.s); - - if ((v1->type == T_IP) && (v2->type == T_NET)) - return ipa_in_netX(v1->val.ip, v2->val.net); - - if ((v1->type == T_NET) && (v2->type == T_NET)) - return net_in_netX(v1->val.net, v2->val.net); - - if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET)) - return trie_match_net(v2->val.ti, v1->val.net); - - if (v2->type != T_SET) - return CMP_ERROR; - - /* With integrated Quad<->IP implicit conversion */ - if ((v1->type == v2->val.t->from.type) || - ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to)))) - return !!find_tree(v2->val.t, v1); - - if (v1->type == T_CLIST) - return clist_match_set(v1->val.ad, v2->val.t); - - if (v1->type == T_ECLIST) - return eclist_match_set(v1->val.ad, v2->val.t); - - if (v1->type == T_LCLIST) - return lclist_match_set(v1->val.ad, v2->val.t); - - if (v1->type == T_PATH) - return as_path_match_set(v1->val.ad, v2->val.t); - - return CMP_ERROR; -} - -/* - * val_format - format filter value - */ -void -val_format(const struct f_val *v, buffer *buf) -{ - char buf2[1024]; - switch (v->type) - { - case T_VOID: buffer_puts(buf, "(void)"); return; - case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return; - case T_INT: buffer_print(buf, "%u", v->val.i); return; - case T_STRING: buffer_print(buf, "%s", v->val.s); return; - case T_IP: buffer_print(buf, "%I", v->val.ip); return; - case T_NET: buffer_print(buf, "%N", v->val.net); return; - case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return; - case T_QUAD: buffer_print(buf, "%R", v->val.i); return; - case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return; - case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return; - case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return; - case T_PREFIX_SET: trie_format(v->val.ti, buf); return; - case T_SET: tree_format(v->val.t, buf); return; - case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return; - case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; - case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; - case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; - case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return; - case T_PATH_MASK: pm_format(v->val.path_mask, buf); return; - default: buffer_print(buf, "[unknown type %x]", v->type); return; - } -} - - static inline void f_cache_eattrs(struct filter_state *fs) { fs->eattrs = &((*fs->rte)->attrs->eattrs); @@ -687,19 +184,6 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) static const char f_dump_line_indent_str[] = " "; -static char val_dump_buffer[1024]; - -static const char * -val_dump(const struct f_val *v) { - static buffer b = { - .start = val_dump_buffer, - .end = val_dump_buffer + 1024, - }; - b.pos = b.start; - val_format(v, &b); - return val_dump_buffer; -} - static void f_dump_line(const struct f_line *dest, int indent); static void @@ -891,122 +375,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2) return 1; } -#if 0 - case FI_ADD: /* fall through */ - 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_PATHMASK_CONSTRUCT: if (!pm_same(f1->a[0].p, f2->a[0].p)) return 0; 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: - THREEARGS; - break; - - case FI_SET: - ARG(2); - { - struct symbol *s1, *s2; - s1 = f1->a[0].p; - s2 = f2->a[0].p; - if (strcmp(s1->name, s2->name)) - return 0; - if (s1->class != s2->class) - return 0; - } - break; - - case FI_CONSTANT: - switch (f1->aux) { - - case T_PREFIX_SET: - if (!trie_same(f1->a[1].p, f2->a[1].p)) - return 0; - break; - - case T_SET: - if (!same_tree(f1->a[1].p, f2->a[1].p)) - return 0; - break; - - case T_STRING: - if (strcmp(f1->a[1].p, f2->a[1].p)) - return 0; - break; - - default: - A2_SAME; - } - break; - - case FI_CONSTANT_INDIRECT: - if (!val_same(* (struct f_val *) f1->a[0].p, * (struct f_val *) f2->a[0].p)) - return 0; - break; - - case FI_VARIABLE: - if (strcmp((char *) f1->a[1].p, (char *) f2->a[1].p)) - return 0; - break; - case FI_PRINT: case FI_LENGTH: ONEARG; break; - case FI_CONDITION: THREEARGS; 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_ROA_MAXLEN: ONEARG; break; - case FI_ROA_ASN: ONEARG; break; - case FI_SADR_SRC: ONEARG; break; - case FI_IP: ONEARG; break; - case FI_IS_V4: ONEARG; break; - case FI_ROUTE_DISTINGUISHER: ONEARG; break; - case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */ - ONEARG; - if (!i_same(f1->a[1].p, f2->a[1].p)) - return 0; - f2->a[1].p = f1->a[1].p; - break; - case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */ - case FI_SWITCH: ONEARG; if (!same_tree(f1->a[1].p, f2->a[1].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; - /* FIXME: ROA check results may change anyway */ - if (strcmp(f1->a[2].rtc->name, - f2->a[2].rtc->name)) - return 0; - break; - case FI_FORMAT: ONEARG; break; - case FI_ASSERT: ONEARG; break; - default: - bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff); -#endif - /** * f_run - run a filter for a route * @filter: filter to run @@ -1133,6 +501,16 @@ f_eval_int(const struct f_line *expr) return val.val.i; } +enum filter_return +f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf) +{ + struct f_val val; + enum filter_return fret = f_eval(expr, tmp_pool, &val); + if (fret > F_RETURN) + val_format(&val, buf); + return fret; +} + /** * filter_same - compare two filters * @new: first filter to be compared diff --git a/filter/filter.h b/filter/filter.h index 9b3886fb..9f1a8e50 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -40,17 +40,13 @@ struct rte; enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool); -enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); uint f_eval_int(const struct f_line *expr); +enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf); char *filter_name(struct filter *filter); int filter_same(struct filter *new, struct filter *old); int f_same(const struct f_line *f1, const struct f_line *f2); -int val_compare(const struct f_val *v1, const struct f_val *v2); - -void val_format(const struct f_val *v, buffer *buf); - #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) #define FILTER_UNDEF ((void *) 2) /* Used in BGP */ diff --git a/nest/cmds.c b/nest/cmds.c index 2b83033f..da4015cf 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -15,7 +15,6 @@ #include "lib/string.h" #include "lib/resource.h" #include "filter/filter.h" -#include "filter/data.h" extern int shutting_down; extern int configuring; @@ -98,16 +97,14 @@ cmd_show_memory(void) void cmd_eval(const struct f_line *expr) { - /* TODO: Return directly the string from eval */ - struct f_val v; - if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN) + buffer buf; + LOG_BUFFER_INIT(buf); + + if (f_eval_buf(expr, this_cli->parser_pool, &buf) > F_RETURN) { cli_msg(8008, "runtime error"); return; } - buffer buf; - LOG_BUFFER_INIT(buf); - val_format(&v, &buf); cli_msg(23, "%s", buf.start); } From 041608129ab15b5eab6fb607c45ddd2d748295b5 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 12 Feb 2019 11:31:18 +0100 Subject: [PATCH 27/88] Filter generator: workaround for M4 claiming all the put-around code be on one line --- filter/decl.m4 | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 7ff22c2e..90ba4ff9 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -14,9 +14,11 @@ m4_divert(-1)m4_dnl # 3 constructors # # Per-inst Diversions: -# 11 content of struct f_inst_FI_... -# 12 constructor arguments -# 13 constructor body +# 101 content of struct f_inst_FI_... +# 102 constructor arguments +# 103 constructor body +# +# Put-around Diversions: 9xx # Flush the completed instruction m4_define(FID_END, `m4_divert(-1)') @@ -33,7 +35,7 @@ m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') -m4_define(FID_ALL, `/* fidall */m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') +m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') @@ -109,9 +111,15 @@ m4_define(COUNT, `FID_MEMBER(uint, count)') m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree)') m4_define(STRING, `FID_MEMBER(const char *, s)') -m4_m4wrap(` -INST_FLUSH() -m4_divert(0) +m4_define(FID_WR_UNDIVERT_LIST,FID_WR_DPUT(900)) +m4_define(FID_WR_CUR_DIRECT,900) +m4_define(FID_WR_PUT, `m4_ifelse(1, m4_eval(m4_divnum > -1), [[m4_divert(-1) + m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1)) + m4_define([[FID_WR_UNDIVERT_LIST]], FID_WR_UNDIVERT_LIST[[]]/* wrput $1 */FID_WR_DPUT($1)/* wrputdir FID_WR_CUR_DIRECT */FID_WR_DPUT(FID_WR_CUR_DIRECT)) + m4_divert(FID_WR_CUR_DIRECT)]], [[m4_define([[FID_WR_UNDIVERT_LIST]], FID_WR_UNDIVERT_LIST[[]]/* wrdrop $1 */FID_WR_DROP($1))]])') + +m4_changequote([[,]]) +m4_divert(900) FID_C #include "nest/bird.h" #include "filter/filter.h" @@ -119,11 +127,11 @@ FID_C FID_H /* Filter instruction codes */ enum f_instruction_code { -m4_undivert(4) +FID_WR_PUT(4) }; /* Per-instruction structures */ -m4_undivert(1) +FID_WR_PUT(1) struct f_inst { const struct f_inst *next; /* Next instruction */ @@ -131,13 +139,16 @@ struct f_inst { int size; /* How many instructions are underneath */ int lineno; /* Line number */ union { - m4_undivert(2) + FID_WR_PUT(2) }; }; FID_ALL /* Instruction constructors */ -m4_undivert(3) -') +FID_WR_PUT(3) +m4_divert(-1) +m4_changequote(`,') + +m4_m4wrap(`INST_FLUSH()m4_define(FID_WR_DPUT, [[m4_undivert($1)]])m4_define(FID_WR_DROP, [[m4_divert(-1)m4_undivert($1)m4_divert(0)]])m4_divert(0)FID_WR_UNDIVERT_LIST[[]]m4_divert(-1)') m4_changequote([[,]]) From b256f241459c51224a4bf428f4bc5dfa44882920 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 12 Feb 2019 11:35:41 +0100 Subject: [PATCH 28/88] Filter: auto-generating enum-to-string --- filter/decl.m4 | 24 +++++++++++++++++ filter/filter.c | 69 ------------------------------------------------- 2 files changed, 24 insertions(+), 69 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 90ba4ff9..9c35677e 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -9,6 +9,7 @@ m4_divert(-1)m4_dnl # # Global Diversions: # 4 enum fi_code +# 5 enum fi_code to string # 1 struct f_inst_FI_... # 2 union in struct f_inst # 3 constructors @@ -30,6 +31,7 @@ m4_define(FID_STRUCT, `FID_ZONE(1, Per-instruction structure)') m4_define(FID_UNION, `FID_ZONE(2, Union member)') m4_define(FID_NEW, `FID_ZONE(3, Constructor)') m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') +m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') @@ -43,6 +45,8 @@ m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL, [[m4_define(FID_CURDIV, m4_d m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ FID_ENUM INST_NAME(), +FID_ENUM_STR +[INST_NAME()] = "INST_NAME()", FID_STRUCT struct f_inst_[[]]INST_NAME() { m4_undivert(101) @@ -124,12 +128,32 @@ FID_C #include "nest/bird.h" #include "filter/filter.h" #include "filter/f-inst.h" + FID_H + /* Filter instruction codes */ enum f_instruction_code { FID_WR_PUT(4) }; +FID_C + +/* Instruction codes to string */ +static const char * const f_instruction_name_str[] = { +FID_WR_PUT(5) +}; + +const char * +f_instruction_name(enum f_instruction_code fi) +{ + if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0]))) + return f_instruction_name_str[fi]; + else + bug("Got unknown instruction code: %d", fi); +} + +FID_H + /* Per-instruction structures */ FID_WR_PUT(1) diff --git a/filter/filter.c b/filter/filter.c index 0bcf9836..ebd2e4dc 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -62,75 +62,6 @@ struct filter_state { void (*bt_assert_hook)(int result, const struct f_line_item *assert); -static const char * const f_instruction_name_str[] = { - /* TODO: Make this better */ - [FI_ADD] = "FI_ADD", - [FI_SUBTRACT] = "FI_SUBTRACT", - [FI_MULTIPLY] = "FI_MULTIPLY", - [FI_DIVIDE] = "FI_DIVIDE", - [FI_AND] = "FI_AND", - [FI_OR] = "FI_OR", - [FI_PAIR_CONSTRUCT] = "FI_PAIR_CONSTRUCT", - [FI_EC_CONSTRUCT] = "FI_EC_CONSTRUCT", - [FI_LC_CONSTRUCT] = "FI_LC_CONSTRUCT", - [FI_PATHMASK_CONSTRUCT] = "FI_PATHMASK_CONSTRUCT", - [FI_NEQ] = "FI_NEQ", - [FI_EQ] = "FI_EQ", - [FI_LT] = "FI_LT", - [FI_LTE] = "FI_LTE", - [FI_NOT] = "FI_NOT", - [FI_MATCH] = "FI_MATCH", - [FI_NOT_MATCH] = "FI_NOT_MATCH", - [FI_DEFINED] = "FI_DEFINED", - [FI_TYPE] = "FI_TYPE", - [FI_IS_V4] = "FI_IS_V4", - [FI_SET] = "FI_SET", - [FI_CONSTANT] = "FI_CONSTANT", - [FI_VARIABLE] = "FI_VARIABLE", - [FI_CONSTANT_INDIRECT] = "FI_CONSTANT_INDIRECT", - [FI_PRINT] = "FI_PRINT", - [FI_CONDITION] = "FI_CONDITION", - [FI_PRINT_AND_DIE] = "FI_PRINT_AND_DIE", - [FI_RTA_GET] = "FI_RTA_GET", - [FI_RTA_SET] = "FI_RTA_SET", - [FI_EA_GET] = "FI_EA_GET", - [FI_EA_SET] = "FI_EA_SET", - [FI_EA_UNSET] = "FI_EA_UNSET", - [FI_PREF_GET] = "FI_PREF_GET", - [FI_PREF_SET] = "FI_PREF_SET", - [FI_LENGTH] = "FI_LENGTH", - [FI_SADR_SRC] = "FI_SADR_SRC", - [FI_ROA_MAXLEN] = "FI_ROA_MAXLEN", - [FI_ROA_ASN] = "FI_ROA_ASN", - [FI_IP] = "FI_IP", - [FI_ROUTE_DISTINGUISHER] = "FI_ROUTE_DISTINGUISHER", - [FI_AS_PATH_FIRST] = "FI_AS_PATH_FIRST", - [FI_AS_PATH_LAST] = "FI_AS_PATH_LAST", - [FI_AS_PATH_LAST_NAG] = "FI_AS_PATH_LAST_NAG", - [FI_RETURN] = "FI_RETURN", - [FI_CALL] = "FI_CALL", - [FI_DROP_RESULT] = "FI_DROP_RESULT", - [FI_SWITCH] = "FI_SWITCH", - [FI_IP_MASK] = "FI_IP_MASK", - [FI_PATH_PREPEND] = "FI_PATH_PREPEND", - [FI_CLIST_ADD] = "FI_CLIST_ADD", - [FI_CLIST_DEL] = "FI_CLIST_DEL", - [FI_CLIST_FILTER] = "FI_CLIST_FILTER", - [FI_ROA_CHECK_IMPLICIT] = "FI_ROA_CHECK_IMPLICIT", - [FI_ROA_CHECK_EXPLICIT] = "FI_ROA_CHECK_EXPLICIT", - [FI_FORMAT] = "FI_FORMAT", - [FI_ASSERT] = "FI_ASSERT", -}; - -const char * -f_instruction_name(enum f_instruction_code fi) -{ - if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0]))) - return f_instruction_name_str[fi]; - else - bug("Got unknown instruction code: %d", fi); -} - static inline void f_cache_eattrs(struct filter_state *fs) { fs->eattrs = &((*fs->rte)->attrs->eattrs); From de12cd18fb213ee9cc872fec77b789f34cfd7cc4 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 12 Feb 2019 14:16:28 +0100 Subject: [PATCH 29/88] Filter: Merged filter line item dumpers into common generated source --- filter/Makefile | 7 ++- filter/decl.m4 | 125 +++++++++++++++++++++++++++++++++++------------- filter/dump.m4 | 51 -------------------- filter/filter.c | 30 +----------- filter/filter.h | 15 ++++++ nest/a-set.c | 13 ++--- nest/attrs.h | 8 ++++ 7 files changed, 123 insertions(+), 126 deletions(-) delete mode 100644 filter/dump.m4 diff --git a/filter/Makefile b/filter/Makefile index df7ff3f9..e3b7ec26 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -22,11 +22,10 @@ $(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@ -$(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c $(o)inst-gen.h +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)inst-gen.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) tests_objs := $(tests_objs) $(src-o-files) + +$(call clean,inst-gen.h inst-gen.c) diff --git a/filter/decl.m4 b/filter/decl.m4 index 9c35677e..6199d4be 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -10,6 +10,8 @@ m4_divert(-1)m4_dnl # Global Diversions: # 4 enum fi_code # 5 enum fi_code to string +# 6 dump line item +# 7 dump line item callers # 1 struct f_inst_FI_... # 2 union in struct f_inst # 3 constructors @@ -18,8 +20,10 @@ m4_divert(-1)m4_dnl # 101 content of struct f_inst_FI_... # 102 constructor arguments # 103 constructor body +# 104 dump line item content # -# Put-around Diversions: 9xx +# Diversions for TARGET=C: 8xx +# Diversions for TARGET=H: 9xx # Flush the completed instruction m4_define(FID_END, `m4_divert(-1)') @@ -32,10 +36,13 @@ m4_define(FID_UNION, `FID_ZONE(2, Union member)') m4_define(FID_NEW, `FID_ZONE(3, Constructor)') m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') +m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') +m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') +m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define(FID_DUMP_BODY_EXISTS)') m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') @@ -57,7 +64,9 @@ FID_NEW struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code m4_undivert(102) ) -FID_H ; FID_C +FID_H +; +FID_C { struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); what_->fi_code = fi_code; @@ -67,6 +76,19 @@ FID_H ; FID_C m4_undivert(103) return what_; } + +FID_DUMP_CALLER +case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; + +FID_DUMP +m4_ifdef([[FID_DUMP_BODY_EXISTS]], +[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item, const int indent)]] +, +[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) +m4_undefine([[FID_DUMP_BODY_EXISTS]]) +{ +m4_undivert(104) +} FID_ALL FID_END ]])') @@ -80,23 +102,32 @@ FID_NEW_ARGS , $1 $2 FID_NEW_BODY what->$2 = $2; +m4_ifelse($3,,,[[ +FID_DUMP_BODY +debug("%s$3\n", INDENT, $4); +]]) FID_END') -m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1) +m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_END') -m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1) +m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_END') -m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1)') +m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,) +FID_DUMP_BODY +f_dump_line(item->lines[$2], indent + 1); +FID_END') m4_define(LINEP, `FID_STRUCT_IN const struct f_line *fl$1; +FID_DUMP_BODY +f_dump_line(item->lines[$2], indent + 1) FID_END') -m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym)') -m4_define(VALI, `FID_MEMBER(struct f_val, vali)') -m4_define(VALP, `FID_MEMBER(const struct f_val *, valp)') +m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, symbol %s, item->sym->name)') +m4_define(VALI, `FID_MEMBER(struct f_val, vali, value %s, val_dump(&item->val))') +m4_define(VALP, `FID_MEMBER(const struct f_val *, valp, value %s, val_dump(&item->val))') m4_define(VAR, `m4_dnl FID_STRUCT_IN const struct f_val *valp; @@ -105,39 +136,33 @@ FID_NEW_ARGS , const struct symbol *sym FID_NEW_BODY what->valp = (what->sym = sym)->def; +FID_DUMP_BODY +debug("%svariable %s with value %s\n", INDENT, item->sym->name, val_dump(item->vp)); FID_END') -m4_define(FRET, `FID_MEMBER(enum filter_return, fret)') -m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs)') -m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc)') +m4_define(FRET, `FID_MEMBER(enum filter_return, fret, %s, filter_return_str(item->fret))') +m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ec subtype %s, ec_subtype_str(item->ecs))') +m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, route table %s, item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa)') m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da)') -m4_define(COUNT, `FID_MEMBER(uint, count)') -m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree)') -m4_define(STRING, `FID_MEMBER(const char *, s)') +m4_define(COUNT, `FID_MEMBER(uint, count, number %u, item->count)') +m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree %p, item->tree)') +m4_define(STRING, `FID_MEMBER(const char *, s, string \"%s\", item->s)') -m4_define(FID_WR_UNDIVERT_LIST,FID_WR_DPUT(900)) -m4_define(FID_WR_CUR_DIRECT,900) -m4_define(FID_WR_PUT, `m4_ifelse(1, m4_eval(m4_divnum > -1), [[m4_divert(-1) - m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1)) - m4_define([[FID_WR_UNDIVERT_LIST]], FID_WR_UNDIVERT_LIST[[]]/* wrput $1 */FID_WR_DPUT($1)/* wrputdir FID_WR_CUR_DIRECT */FID_WR_DPUT(FID_WR_CUR_DIRECT)) - m4_divert(FID_WR_CUR_DIRECT)]], [[m4_define([[FID_WR_UNDIVERT_LIST]], FID_WR_UNDIVERT_LIST[[]]/* wrdrop $1 */FID_WR_DROP($1))]])') +m4_define(FID_WR_PUT_LIST) +m4_define(FID_WR_DROP_LIST) +m4_define(FID_WR_IPUT, `m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1))m4_define([[FID_WR_PUT_LIST]], FID_WR_PUT_LIST[[]]FID_WR_DPUT($1)FID_WR_DPUT(FID_WR_CUR_DIRECT))m4_divert(FID_WR_CUR_DIRECT)') +m4_define(FID_WR_IDROP, `m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1))m4_define([[FID_WR_DROP_LIST]], FID_WR_DROP_LIST[[]]FID_WR_DPUT($1)FID_WR_DPUT(FID_WR_CUR_DIRECT))m4_divert(FID_WR_CUR_DIRECT)') + +m4_define(FID_WR_DIRECT, `m4_define([[FID_WR_CUR_DIRECT]],$1)m4_ifelse(TARGET,[[$2]],[[m4_define([[FID_WR_PUT]], [[FID_WR_IPUT($]][[@)]])m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST[[]]FID_WR_DPUT($1))]],[[m4_define([[FID_WR_PUT]], [[FID_WR_IDROP($]][[@)]])m4_define([[FID_WR_DROP_LIST]],FID_WR_DROP_LIST[[]]FID_WR_DPUT($1))]])m4_divert($1)') + +m4_dnl m4_define(FID_WR_CUR_DIRECT,m4_ifelse(TARGET,`C',800,TARGET,`H',900,m4_errprint(`Bad TARGET: 'TARGET)m4_m4exit(1))) m4_changequote([[,]]) -m4_divert(900) -FID_C +FID_WR_DIRECT(800,C) #include "nest/bird.h" #include "filter/filter.h" #include "filter/f-inst.h" -FID_H - -/* Filter instruction codes */ -enum f_instruction_code { -FID_WR_PUT(4) -}; - -FID_C - /* Instruction codes to string */ static const char * const f_instruction_name_str[] = { FID_WR_PUT(5) @@ -152,7 +177,39 @@ f_instruction_name(enum f_instruction_code fi) bug("Got unknown instruction code: %d", fi); } -FID_H +/* Instruction constructors */ +FID_WR_PUT(3) + +/* Line dumpers */ +#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) +static const char f_dump_line_indent_str[] = " "; +void f_dump_line(const struct f_line *dest, int indent); + +FID_WR_PUT(6) + +void f_dump_line(const struct f_line *dest, int indent) +{ + if (!dest) { + debug("%sNo filter line (NULL)\n", INDENT); + return; + } + debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len); + for (uint i=0; ilen; i++) { + const struct f_line_item *item = &dest->items[i]; + debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); + switch (item->fi_code) { +FID_WR_PUT(7) + default: bug("Unknown instruction %x in f_dump_line", item->fi_code); + } + } + debug("%sFilter line %p dump done\n", INDENT, dest); +} + +FID_WR_DIRECT(900,H) +/* Filter instruction codes */ +enum f_instruction_code { +FID_WR_PUT(4) +}; /* Per-instruction structures */ FID_WR_PUT(1) @@ -167,12 +224,12 @@ struct f_inst { }; }; -FID_ALL /* Instruction constructors */ FID_WR_PUT(3) + m4_divert(-1) m4_changequote(`,') -m4_m4wrap(`INST_FLUSH()m4_define(FID_WR_DPUT, [[m4_undivert($1)]])m4_define(FID_WR_DROP, [[m4_divert(-1)m4_undivert($1)m4_divert(0)]])m4_divert(0)FID_WR_UNDIVERT_LIST[[]]m4_divert(-1)') +m4_m4wrap(`INST_FLUSH()m4_define(FID_WR_DPUT, [[m4_undivert($1)]])m4_divert(0)FID_WR_PUT_LIST[[]]m4_divert(-1)FID_WR_DROP_LIST[[]]') m4_changequote([[,]]) diff --git a/filter/dump.m4 b/filter/dump.m4 deleted file mode 100644 index 4ea3e3be..00000000 --- a/filter/dump.m4 +++ /dev/null @@ -1,51 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Dumping instruction lines -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -case INST_NAME(): -m4_undivert(2) -break; -m4_divert(-1) -]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(LINE, `m4_divert(2)f_dump_line(item->lines[$2], indent + 1); -m4_divert(-1)') -m4_define(LINEP, `LINE($@)') -m4_define(SYMBOL, `m4_divert(2)debug("%ssymbol %s\n", INDENT, item->sym->name); -m4_divert(-1)') -m4_define(VALI, `m4_divert(2)debug("%svalue %s\n", INDENT, val_dump(&item->val)); -m4_divert(-1)') -m4_define(VAR, `m4_divert(2)debug("%svar %s: value %s\n", INDENT, item->sym->name, val_dump(item->vp)); -m4_divert(-1)') -m4_define(FRET, `m4_divert(2)debug("%sfilter return value %d\n", INDENT, item->fret); -m4_divert(-1)') -m4_define(ECS, `m4_divert(2)debug("%sec subtype %d\n", INDENT, item->ecs); -m4_divert(-1)') -m4_define(RTC, `m4_divert(2)debug("%sroute table %s\n", INDENT, item->rtc->name); -m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(2)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly); -m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(2)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code); -m4_divert(-1)') -m4_define(DUMP, `m4_divert(2)$1m4_divert(-1)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) - -default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff); -') - -m4_changequote([[,]]) diff --git a/filter/filter.c b/filter/filter.c index ebd2e4dc..f08c91db 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -112,34 +112,6 @@ val_format_str(struct filter_state *fs, struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) -static const char f_dump_line_indent_str[] = " "; - -static void f_dump_line(const struct f_line *dest, int indent); - -static void -f_dump_line_item(const struct f_line_item *item, int indent) -{ - debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); - switch (item->fi_code) { -#include "filter/f-inst-dump.c" - } -} - -static void -f_dump_line(const struct f_line *dest, int indent) -{ - if (!dest) { - debug("%sNo filter line (NULL)\n", INDENT); - return; - } - debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len); - for (uint i=0; ilen; i++) - f_dump_line_item(&dest->items[i], indent+1); - debug("%sFilter line %p dump done\n", INDENT, dest); -#undef INDENT -} - static uint postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) { @@ -166,7 +138,7 @@ f_postfixify_concat(const struct f_inst * const inst[], uint count) out->len = postfixify(out, inst[i], out->len); #if DEBUGGING - f_dump_line(out, 0); +// f_dump_line(out, 0); #endif return out; } diff --git a/filter/filter.h b/filter/filter.h index 9f1a8e50..d03c6438 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -27,6 +27,21 @@ enum filter_return { F_QUITBIRD, }; +static inline const char *filter_return_str(const enum filter_return fret) { + switch (fret) { +#define FRS(x) case x: return #x + FRS(F_NOP); + FRS(F_NONL); + FRS(F_RETURN); + FRS(F_ACCEPT); + FRS(F_REJECT); + FRS(F_ERROR); + FRS(F_QUITBIRD); +#undef FRS + default: bug("This shall not happen"); + } +} + struct f_val; /* The filter encapsulating structure to be pointed-to from outside */ diff --git a/nest/a-set.c b/nest/a-set.c index 10ddd139..78922ffd 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -72,15 +72,12 @@ ec_format(byte *buf, u64 ec) char tbuf[16], *kind; type = ec >> 48; - switch (type & 0xf0ff) - { - case EC_RT: kind = "rt"; break; - case EC_RO: kind = "ro"; break; + kind = ec_subtype_str(type & 0xf0ff); - default: - kind = tbuf; - bsprintf(kind, "unknown 0x%x", type); - } + if (!kind) { + kind = tbuf; + bsprintf(kind, "unknown 0x%x", type); + } switch (ec >> 56) { diff --git a/nest/attrs.h b/nest/attrs.h index 37227d9b..4efcff79 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -125,6 +125,14 @@ enum ec_subtype { EC_GENERIC = 0xFFFF, }; +static inline const char *ec_subtype_str(const enum ec_subtype ecs) { + switch (ecs) { + case EC_RT: return "rt"; + case EC_RO: return "ro"; + default: return NULL; + } +} + /* Transitive bit (for first u32 half of EC) */ #define EC_TBIT 0x40000000 From dd4d409551ae22d0a9bf4e3a6edc6fb9656911b9 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 12 Feb 2019 20:37:32 +0100 Subject: [PATCH 30/88] Filter: Merged postfixify routine --- filter/Makefile | 5 +-- filter/decl.m4 | 102 ++++++++++++++++++++++++++++++++++++------- filter/f-inst.c | 24 +++++----- filter/filter.c | 31 ------------- filter/interpret.m4 | 2 +- filter/postfixify.m4 | 68 ----------------------------- nest/a-set.c | 5 ++- 7 files changed, 103 insertions(+), 134 deletions(-) delete mode 100644 filter/postfixify.m4 diff --git a/filter/Makefile b/filter/Makefile index e3b7ec26..4f515864 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -7,9 +7,6 @@ $(conf-y-targets) $(conf-lex-targets) $(src-o-files): $(o)inst-gen.h M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) -$(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ @@ -22,7 +19,7 @@ $(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)inst-gen.h +$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-same.c $(o)inst-gen.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/decl.m4 b/filter/decl.m4 index 6199d4be..4670de33 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -12,6 +12,7 @@ m4_divert(-1)m4_dnl # 5 enum fi_code to string # 6 dump line item # 7 dump line item callers +# 8 postfixify # 1 struct f_inst_FI_... # 2 union in struct f_inst # 3 constructors @@ -21,6 +22,7 @@ m4_divert(-1)m4_dnl # 102 constructor arguments # 103 constructor body # 104 dump line item content +# 105 postfixify body # # Diversions for TARGET=C: 8xx # Diversions for TARGET=H: 9xx @@ -38,11 +40,13 @@ m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') +m4_define(FID_POSTFIXIFY, `FID_ZONE(8, Postfixify)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') -m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define(FID_DUMP_BODY_EXISTS)') +m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') +m4_define(FID_POSTFIXIFY_BODY, `m4_divert(105)m4_define([[FID_POSTFIXIFY_BODY_EXISTS]])') m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') @@ -90,11 +94,28 @@ m4_undefine([[FID_DUMP_BODY_EXISTS]]) m4_undivert(104) } FID_ALL + +FID_POSTFIXIFY +case INST_NAME(): { +m4_ifdef([[FID_POSTFIXIFY_BODY_EXISTS]], [[const struct f_inst_]]INST_NAME()[[ *what = &(what_->i_]]INST_NAME()[[);]], [[]]) + m4_undivert(105) + dest->items[pos].fi_code = what_->fi_code; + dest->items[pos].lineno = what_->lineno; + break; +} +m4_undefine([[FID_POSTFIXIFY_BODY_EXISTS]]) + FID_END ]])') m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') +m4_dnl FID_MEMBER call: +m4_dnl type +m4_dnl name in f_inst +m4_dnl name in f_line_item +m4_dnl dump format string +m4_dnl dump format args m4_define(FID_MEMBER, `m4_dnl FID_STRUCT_IN $1 $2; @@ -103,31 +124,46 @@ FID_NEW_ARGS FID_NEW_BODY what->$2 = $2; m4_ifelse($3,,,[[ +FID_POSTFIXIFY_BODY +dest->items[pos].$3 = what->$2; +]]) +m4_ifelse($4,,,[[ FID_DUMP_BODY -debug("%s$3\n", INDENT, $4); +debug("%s$4\n", INDENT, $5); ]]) FID_END') -m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,) +m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; +FID_POSTFIXIFY_BODY +pos = postfixify(dest, what->f$1, pos); FID_END') -m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,) +m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; +FID_POSTFIXIFY_BODY +pos = postfixify(dest, what->f$1, pos); FID_END') -m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,) +m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,,) FID_DUMP_BODY f_dump_line(item->lines[$2], indent + 1); +FID_POSTFIXIFY_BODY +dest->items[pos].lines[$2] = f_postfixify(what->f$1); FID_END') m4_define(LINEP, `FID_STRUCT_IN const struct f_line *fl$1; FID_DUMP_BODY f_dump_line(item->lines[$2], indent + 1) +FID_POSTFIXIFY_BODY +dest->items[pos].lines[$2] = what->fl$1; +FID_END') +m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, symbol %s, item->sym->name)') +m4_define(VALI, `FID_MEMBER(struct f_val, vali, val, value %s, val_dump(&item->val))') +m4_define(VALP, `FID_MEMBER(const struct f_val *, valp,, value %s, val_dump(&item->val)) +FID_POSTFIXIFY_BODY +dest->items[pos].val = *(what->valp); FID_END') -m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, symbol %s, item->sym->name)') -m4_define(VALI, `FID_MEMBER(struct f_val, vali, value %s, val_dump(&item->val))') -m4_define(VALP, `FID_MEMBER(const struct f_val *, valp, value %s, val_dump(&item->val))') m4_define(VAR, `m4_dnl FID_STRUCT_IN const struct f_val *valp; @@ -136,17 +172,19 @@ FID_NEW_ARGS , const struct symbol *sym FID_NEW_BODY what->valp = (what->sym = sym)->def; +FID_POSTFIXIFY_BODY +dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; FID_DUMP_BODY debug("%svariable %s with value %s\n", INDENT, item->sym->name, val_dump(item->vp)); FID_END') -m4_define(FRET, `FID_MEMBER(enum filter_return, fret, %s, filter_return_str(item->fret))') -m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ec subtype %s, ec_subtype_str(item->ecs))') -m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, route table %s, item->rtc->name)') -m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da)') -m4_define(COUNT, `FID_MEMBER(uint, count, number %u, item->count)') -m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree %p, item->tree)') -m4_define(STRING, `FID_MEMBER(const char *, s, string \"%s\", item->s)') +m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, %s, filter_return_str(item->fret))') +m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, ec subtype %s, ec_subtype_str(item->ecs))') +m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, route table %s, item->rtc->name)') +m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da)') +m4_define(COUNT, `FID_MEMBER(uint, count, count, number %u, item->count)') +m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, tree %p, item->tree)') +m4_define(STRING, `FID_MEMBER(const char *, s, s, string \"%s\", item->s)') m4_define(FID_WR_PUT_LIST) m4_define(FID_WR_DROP_LIST) @@ -205,6 +243,38 @@ FID_WR_PUT(7) debug("%sFilter line %p dump done\n", INDENT, dest); } +/* Postfixify */ +static uint +postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) +{ + for ( ; what_; what_ = what_->next) { + switch (what_->fi_code) { +FID_WR_PUT(8) + } + pos++; + } + return pos; +} + +struct f_line * +f_postfixify_concat(const struct f_inst * const inst[], uint count) +{ + uint len = 0; + for (uint i=0; inext) + len += what->size; + + struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len); + + for (uint i=0; ilen = postfixify(out, inst[i], out->len); + +#if DEBUGGING + f_dump_line(out, 0); +#endif + return out; +} + FID_WR_DIRECT(900,H) /* Filter instruction codes */ enum f_instruction_code { diff --git a/filter/f-inst.c b/filter/f-inst.c index 96d6108c..7d2641c2 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -269,18 +269,18 @@ LINE(3,1); } INST(FI_PRINT_AND_DIE, 0, 0) { - POSTFIXIFY([[ - { - uint opos = pos; - ]]); + FID_POSTFIXIFY_BODY + { + uint opos = pos; + FID_END ARG_ANY(1); - POSTFIXIFY([[ - if (opos < pos) - dest->items[pos].flags |= FIF_PRINTED; - } - ]]); + FID_POSTFIXIFY_BODY + if (opos < pos) + dest->items[pos].flags |= FIF_PRINTED; + } + FID_END FRET(2); @@ -708,9 +708,9 @@ } /* Postfixify extracts the function body from the symbol */ - POSTFIXIFY([[ - dest->items[pos].lines[0] = what->sym->def; - ]]); + FID_POSTFIXIFY_BODY + dest->items[pos].lines[0] = what->sym->def; + FID_END /* First push the body on stack */ LINEX(what->lines[0]); diff --git a/filter/filter.c b/filter/filter.c index f08c91db..d80309b8 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -112,37 +112,6 @@ val_format_str(struct filter_state *fs, struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -static uint -postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) -{ - for ( ; what_; what_ = what_->next) { - switch (what_->fi_code) { -#include "filter/f-inst-postfixify.c" - } - pos++; - } - return pos; -} - -struct f_line * -f_postfixify_concat(const struct f_inst * const inst[], uint count) -{ - uint len = 0; - for (uint i=0; inext) - len += what->size; - - struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len); - - for (uint i=0; ilen = postfixify(out, inst[i], out->len); - -#if DEBUGGING -// f_dump_line(out, 0); -#endif - return out; -} - /** * interpret * @fs: filter state diff --git a/filter/interpret.m4 b/filter/interpret.m4 index e32b3a76..eb368b41 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -62,11 +62,11 @@ m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da') m4_define(TREE, `') m4_define(STRING, `') m4_define(COUNT, `') -m4_define(POSTFIXIFY, `') m4_define(SAME, `') m4_define(FID_STRUCT_IN, `m4_divert(-1)') m4_define(FID_NEW_ARGS, `m4_divert(-1)') m4_define(FID_NEW_BODY, `m4_divert(-1)') +m4_define(FID_POSTFIXIFY_BODY, `m4_divert(-1)') m4_define(FID_END, `m4_divert(2)') m4_m4wrap(` diff --git a/filter/postfixify.m4 b/filter/postfixify.m4 deleted file mode 100644 index 853c9a51..00000000 --- a/filter/postfixify.m4 +++ /dev/null @@ -1,68 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Converting instructions trees to instruction lines -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -case INST_NAME(): -#define what ((const struct f_inst_]]INST_NAME()[[ *) &(what_->i_]]INST_NAME()[[)) -m4_undivert(2) -#undef what -dest->items[pos].fi_code = what_->fi_code; -dest->items[pos].lineno = what_->lineno; -break; -m4_divert(-1) -]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(ARG, `m4_divert(2)pos = postfixify(dest, what->f$1, pos); -m4_divert(-1)') -m4_define(ARG_ANY, `m4_divert(2)pos = postfixify(dest, what->f$1, pos); -m4_divert(-1)') -m4_define(LINE, `m4_divert(2)dest->items[pos].lines[$2] = f_postfixify(what->f$1); -m4_divert(-1)') -m4_define(LINEP, `m4_divert(2)dest->items[pos].lines[$2] = what->fl$1; -m4_divert(-1)') -m4_define(SYMBOL, `m4_divert(2)dest->items[pos].sym = what->sym; -m4_divert(-1)') -m4_define(VALI, `m4_divert(2)dest->items[pos].val = what->vali; -m4_divert(-1)') -m4_define(VALP, `m4_divert(2)dest->items[pos].val = *(what->valp); -m4_divert(-1)') -m4_define(VAR, `m4_divert(2)dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; -m4_divert(-1)') -m4_define(FRET, `m4_divert(2)dest->items[pos].fret = what->fret; -m4_divert(-1)') -m4_define(ECS, `m4_divert(2)dest->items[pos].ecs = what->ecs; -m4_divert(-1)') -m4_define(RTC, `m4_divert(2)dest->items[pos].rtc = what->rtc; -m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(2)dest->items[pos].sa = what->sa; -m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(2)dest->items[pos].da = what->da; -m4_divert(-1)') -m4_define(COUNT, `m4_divert(2)dest->items[pos].count = what->count; -m4_divert(-1)') -m4_define(TREE, `m4_divert(2)dest->items[pos].tree = what->tree; -m4_divert(-1)') -m4_define(STRING, `m4_divert(2)dest->items[pos].s = what->s; -m4_divert(-1)') -m4_define(POSTFIXIFY, `m4_divert(2)$1m4_divert(-1)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) - -default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff); -') - -m4_changequote([[,]]) diff --git a/nest/a-set.c b/nest/a-set.c index 78922ffd..1186eb56 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -69,14 +69,15 @@ int ec_format(byte *buf, u64 ec) { u32 type, key, val; - char tbuf[16], *kind; + char tbuf[16]; + const char *kind; type = ec >> 48; kind = ec_subtype_str(type & 0xf0ff); if (!kind) { + bsprintf(tbuf, "unknown 0x%x", type); kind = tbuf; - bsprintf(kind, "unknown 0x%x", type); } switch (ec >> 56) From 132529ce8908661fd2baa0758c335006fb039ef0 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 13 Feb 2019 12:25:30 +0100 Subject: [PATCH 31/88] Filter: merged filter compare functions into common M4 file --- filter/Makefile | 5 +-- filter/config.Y | 17 ++++++++-- filter/data.c | 49 +++++++++++++++++------------ filter/decl.m4 | 75 +++++++++++++++++++++++++++++++++++--------- filter/f-inst.c | 2 ++ filter/f-inst.h | 2 ++ filter/filter.c | 27 ---------------- filter/filter_test.c | 18 ++++++++--- filter/same.m4 | 63 ------------------------------------- filter/test.conf | 14 +++++++-- 10 files changed, 134 insertions(+), 138 deletions(-) delete mode 100644 filter/same.m4 diff --git a/filter/Makefile b/filter/Makefile index 4f515864..65602ea8 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -10,16 +10,13 @@ M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ -$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - $(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=H -P $^ >$@ $(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-same.c $(o)inst-gen.h +$(o)filter.o: $(o)f-inst-interpret.c $(o)inst-gen.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/filter/config.Y b/filter/config.Y index 42624f44..488b9ced 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -441,7 +441,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, - BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, FORMAT) + BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) %nonassoc THEN %nonassoc ELSE @@ -489,7 +489,7 @@ custom_attr: ATTRIBUTE type CF_SYM_VOID ';' { conf: bt_test_suite ; bt_test_suite: BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' { - struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite)); + struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); t->fn = $3->def; t->fn_name = $3->name; t->dsc = $5; @@ -498,6 +498,19 @@ bt_test_suite: } ; +conf: bt_test_same ; +bt_test_same: + BT_TEST_SAME '(' CF_SYM_FUNCTION ',' CF_SYM_FUNCTION ',' NUM ')' { + struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); + t->fn = $3->def; + t->cmp = $5->def; + t->result = $7; + t->fn_name = $3->name; + t->dsc = $5->name; + add_tail(&new_config->tests, &t->n); + } + ; + type: INT { $$ = T_INT; } | BOOL { $$ = T_BOOL; } diff --git a/filter/data.c b/filter/data.c index b389b8e8..912e2b00 100644 --- a/filter/data.c +++ b/filter/data.c @@ -146,34 +146,41 @@ val_compare(const struct f_val *v1, const struct f_val *v2) } } +static inline int +pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2) +{ + if (mi1->kind != mi2->kind) + return 0; + + switch (mi1->kind) { + case PM_ASN: + if (mi1->asn != mi2->asn) + return 0; + break; + case PM_ASN_EXPR: + if (!f_same(mi1->expr, mi2->expr)) + return 0; + break; + case PM_ASN_RANGE: + if (mi1->from != mi2->from) + return 0; + if (mi1->to != mi2->to) + return 0; + break; + } + + return 1; +} + static int pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2) { if (m1->len != m2->len) for (uint i=0; ilen; i++) - { - if (m1->item[i].kind != m2->item[i].kind) + if (!pmi_same(&(m1->item[i]), &(m2->item[i]))) return 0; - switch (m1->item[i].kind) { - case PM_ASN: - if (m1->item[i].asn != m2->item[i].asn) - return 0; - break; - case PM_ASN_EXPR: - if (!f_same(m1->item[i].expr, m2->item[i].expr)) - return 0; - break; - case PM_ASN_RANGE: - if (m1->item[i].from != m2->item[i].from) - return 0; - if (m1->item[i].to != m2->item[i].to) - return 0; - break; - } - } - return 1; } @@ -200,6 +207,8 @@ val_same(const struct f_val *v1, const struct f_val *v2) switch (v1->type) { case T_PATH_MASK: return pm_same(v1->val.path_mask, v2->val.path_mask); + case T_PATH_MASK_ITEM: + return pmi_same(&(v1->val.pmi), &(v2->val.pmi)); case T_PATH: case T_CLIST: case T_ECLIST: diff --git a/filter/decl.m4 b/filter/decl.m4 index 4670de33..5ac62cbd 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -13,6 +13,7 @@ m4_divert(-1)m4_dnl # 6 dump line item # 7 dump line item callers # 8 postfixify +# 9 same (filter comparator) # 1 struct f_inst_FI_... # 2 union in struct f_inst # 3 constructors @@ -23,6 +24,7 @@ m4_divert(-1)m4_dnl # 103 constructor body # 104 dump line item content # 105 postfixify body +# 106 comparator body # # Diversions for TARGET=C: 8xx # Diversions for TARGET=H: 9xx @@ -41,12 +43,14 @@ m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') m4_define(FID_POSTFIXIFY, `FID_ZONE(8, Postfixify)') +m4_define(FID_SAME, `FID_ZONE(9, Comparison)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') m4_define(FID_POSTFIXIFY_BODY, `m4_divert(105)m4_define([[FID_POSTFIXIFY_BODY_EXISTS]])') +m4_define(FID_SAME_BODY, `m4_divert(106)') m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') @@ -105,6 +109,11 @@ m4_ifdef([[FID_POSTFIXIFY_BODY_EXISTS]], [[const struct f_inst_]]INST_NAME()[[ * } m4_undefine([[FID_POSTFIXIFY_BODY_EXISTS]]) +FID_SAME +case INST_NAME(): +m4_undivert(106) +break; + FID_END ]])') @@ -114,6 +123,7 @@ m4_dnl FID_MEMBER call: m4_dnl type m4_dnl name in f_inst m4_dnl name in f_line_item +m4_dnl comparator for same m4_dnl dump format string m4_dnl dump format args m4_define(FID_MEMBER, `m4_dnl @@ -128,24 +138,28 @@ FID_POSTFIXIFY_BODY dest->items[pos].$3 = what->$2; ]]) m4_ifelse($4,,,[[ +FID_SAME_BODY +if ($4) return 0; +]]) +m4_ifelse($5,,,[[ FID_DUMP_BODY -debug("%s$4\n", INDENT, $5); +debug("%s$5\n", INDENT, $6); ]]) FID_END') -m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,,) +m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_POSTFIXIFY_BODY pos = postfixify(dest, what->f$1, pos); FID_END') -m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,,) +m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,,,) FID_NEW_BODY for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_POSTFIXIFY_BODY pos = postfixify(dest, what->f$1, pos); FID_END') -m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,,) +m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,[[!f_same(f1->lines[$2], f2->lines[$2])]],,) FID_DUMP_BODY f_dump_line(item->lines[$2], indent + 1); FID_POSTFIXIFY_BODY @@ -157,10 +171,13 @@ FID_DUMP_BODY f_dump_line(item->lines[$2], indent + 1) FID_POSTFIXIFY_BODY dest->items[pos].lines[$2] = what->fl$1; +FID_SAME_BODY +if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; FID_END') -m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, symbol %s, item->sym->name)') -m4_define(VALI, `FID_MEMBER(struct f_val, vali, val, value %s, val_dump(&item->val))') -m4_define(VALP, `FID_MEMBER(const struct f_val *, valp,, value %s, val_dump(&item->val)) +m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, +[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') +m4_define(VALI, `FID_MEMBER(struct f_val, vali, val, [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val))') +m4_define(VALP, `FID_MEMBER(const struct f_val *, valp,, [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val)) FID_POSTFIXIFY_BODY dest->items[pos].val = *(what->valp); FID_END') @@ -174,17 +191,19 @@ FID_NEW_BODY what->valp = (what->sym = sym)->def; FID_POSTFIXIFY_BODY dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; +FID_SAME_BODY +if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0; FID_DUMP_BODY debug("%svariable %s with value %s\n", INDENT, item->sym->name, val_dump(item->vp)); FID_END') -m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, %s, filter_return_str(item->fret))') -m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, ec subtype %s, ec_subtype_str(item->ecs))') -m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, route table %s, item->rtc->name)') -m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da)') -m4_define(COUNT, `FID_MEMBER(uint, count, count, number %u, item->count)') -m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, tree %p, item->tree)') -m4_define(STRING, `FID_MEMBER(const char *, s, s, string \"%s\", item->s)') +m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret))') +m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs))') +m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') +m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code)') +m4_define(COUNT, `FID_MEMBER(uint, count, count, f1->count != f2->count, number %u, item->count)') +m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree)') +m4_define(STRING, `FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s)') m4_define(FID_WR_PUT_LIST) m4_define(FID_WR_DROP_LIST) @@ -275,6 +294,32 @@ f_postfixify_concat(const struct f_inst * const inst[], uint count) return out; } +/* Filter line comparison */ +int +f_same(const struct f_line *fl1, const struct f_line *fl2) +{ + if ((!fl1) && (!fl2)) + return 1; + if ((!fl1) || (!fl2)) + return 0; + if (fl1->len != fl2->len) + return 0; + for (uint i=0; ilen; i++) { +#define f1 (&(fl1->items[i])) +#define f2 (&(fl2->items[i])) + if (f1->fi_code != f2->fi_code) + return 0; + if (f1->flags != f2->flags) + return 0; + + switch(f1->fi_code) { +FID_WR_PUT(9) + } + } + return 1; +} + + FID_WR_DIRECT(900,H) /* Filter instruction codes */ enum f_instruction_code { diff --git a/filter/f-inst.c b/filter/f-inst.c index 7d2641c2..4ab46529 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -730,6 +730,8 @@ if (count != sym->aux2) cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); FID_END + + /* FIXME: Optimization of function comparison. */ } INST(FI_DROP_RESULT, 1, 0) { diff --git a/filter/f-inst.h b/filter/f-inst.h index ad994857..e1d0b675 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -82,8 +82,10 @@ extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); struct f_bt_test_suite { node n; /* Node in config->tests */ struct f_line *fn; /* Root of function */ + struct f_line *cmp; /* Compare to this function */ const char *fn_name; /* Name of test */ const char *dsc; /* Description */ + int result; /* Desired result */ }; #endif diff --git a/filter/filter.c b/filter/filter.c index d80309b8..29e78204 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -220,33 +220,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) } -/* - * f_same - function that does real comparing of instruction trees, you should call filter_same from outside - */ -int -f_same(const struct f_line *fl1, const struct f_line *fl2) -{ - if ((!fl1) && (!fl2)) - return 1; - if ((!fl1) || (!fl2)) - return 0; - if (fl1->len != fl2->len) - return 0; - for (uint i=0; ilen; i++) { -#define f1 (&(fl1->items[i])) -#define f2 (&(fl2->items[i])) - if (f1->fi_code != f2->fi_code) - return 0; - if (f1->flags != f2->flags) - return 0; - - switch(f1->fi_code) { -#include "filter/f-inst-same.c" - } - } - return 1; -} - /** * f_run - run a filter for a route * @filter: filter to run diff --git a/filter/filter_test.c b/filter/filter_test.c index edd73ac8..d83e8a8b 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -42,13 +42,22 @@ parse_config_file(const void *argv) } static int -run_function(const void *parsed_fn_def) +run_function(const void *arg) { - const struct f_line *f = (const struct f_line *) parsed_fn_def; + const struct f_bt_test_suite *t = arg; + + if (t->cmp) + return t->result == f_same(t->fn, t->cmp); + + if (!f_same(t->fn, t->fn)) { + bt_result = bt_suite_result = 0; + bt_log_suite_case_result(0, "The function doesn't compare to itself as the same"); + return 0; + } linpool *tmp = lp_new_default(&root_pool); struct f_val res; - enum filter_return fret = f_eval(f, tmp, &res); + enum filter_return fret = f_eval(t->fn, tmp, &res); rfree(tmp); return (fret < F_REJECT); @@ -79,6 +88,7 @@ main(int argc, char *argv[]) struct config *c = NULL; struct parse_config_file_arg pcfa = { .cp = &c, .filename = BT_CONFIG_FILE }; bt_test_suite_base(parse_config_file, "conf", (const void *) &pcfa, 0, 0, "parse config file"); + bt_test_suite_base(parse_config_file, "reconf", (const void *) &pcfa, 0, 0, "reconfigure with the same file"); bt_bird_cleanup(); @@ -86,7 +96,7 @@ main(int argc, char *argv[]) { struct f_bt_test_suite *t; WALK_LIST(t, c->tests) - bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc); + bt_test_suite_base(run_function, t->fn_name, t, BT_FORKING, BT_TIMEOUT, "%s", t->dsc); } return bt_exit_value(); diff --git a/filter/same.m4 b/filter/same.m4 deleted file mode 100644 index cf739af4..00000000 --- a/filter/same.m4 +++ /dev/null @@ -1,63 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Filter Comparator Generator -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -case INST_NAME(): -m4_undivert(2) -break; -m4_divert(-1) -]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') - -m4_define(ARG, `') -m4_define(ARG_ANY, `') - -m4_define(LINE, `m4_divert(2)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; -m4_divert(-1)') -m4_define(LINEP, LINE) - -m4_define(SYMBOL, `m4_divert(2){ - const struct symbol *s1 = f1->sym, *s2 = f2->sym; - if (strcmp(s1->name, s2->name)) return 0; - if (s1->class != s2->class) return 0; -} -m4_divert(-1)') - -m4_define(VALI, `m4_divert(2)if (!val_same(f1->vp, f2->vp)) return 0; -m4_divert(-1)') -m4_define(VALP, `m4_divert(2)if (!val_same(f1->vp, f2->vp)) return 0; -m4_divert(-1)') -m4_define(VAR, `SYMBOL()VALP()') - -m4_define(FRET, `m4_divert(2)if (f1->fret != f2->fret) return 0; -m4_divert(-1)') -m4_define(ECS, `m4_divert(2)if (f1->ecs != f2->ecs) return 0; -m4_divert(-1)') -m4_define(RTC, `m4_divert(2)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0; -m4_divert(-1)') -m4_define(STATIC_ATTR, `m4_divert(2)if (f1->sa.sa_code != f2->sa.sa_code) return 0; -m4_divert(-1)') -m4_define(DYNAMIC_ATTR, `m4_divert(2)if (f1->da.ea_code != f2->da.ea_code) return 0; -m4_divert(-1)') - -m4_define(SAME, `m4_divert(2)$1m4_divert(-1)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) -default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff); -') - -m4_changequote([[,]]) - diff --git a/filter/test.conf b/filter/test.conf index e6b6ca4e..89215d1c 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -25,8 +25,19 @@ function onef(int a) return 1; } +function twof(int a) +{ + return 2; +} +function oneg(int a) +{ + return 1; +} +bt_test_same(onef, onef, 1); +bt_test_same(onef, oneg, 1); +bt_test_same(onef, twof, 0); /* * Testing boolean expressions @@ -62,7 +73,6 @@ bt_test_suite(t_bool, "Testing boolean expressions"); - /* * Testing integers * ---------------- @@ -1347,8 +1357,6 @@ filter vpn_filter NET_IP6: print "IPV6"; } -# aoiufahkejtrhaweifdsbhydkfj,ysdnm - bt_check_assign(from, 10.20.30.40); bt_check_assign(gw, 55.55.55.44); From 0b39b1cbb70c6f37a30a3130e1c308ddd0ba36de Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 15 Feb 2019 13:53:17 +0100 Subject: [PATCH 32/88] Conf: Symbol implementation converted from void pointers to union ... and consted some declarations. --- conf/cf-lex.l | 59 ++++++++++++++++++++-------------------------- conf/conf.h | 49 +++++++++++++++++++++++++++++++------- conf/confbase.Y | 5 ++-- filter/config.Y | 53 ++++++++++++++++++++++------------------- filter/decl.m4 | 4 ++-- filter/f-inst.c | 10 ++++---- filter/f-inst.h | 5 ++-- filter/f-util.c | 4 ++-- filter/filter.c | 5 ++-- filter/filter.h | 6 ++--- nest/config.Y | 24 +++++++++---------- nest/proto.c | 6 ++--- nest/protocol.h | 6 ++--- nest/route.h | 4 ++-- nest/rt-table.c | 14 +++++------ proto/mrt/mrt.h | 6 ++--- sysdep/unix/krt.c | 2 +- sysdep/unix/main.c | 8 +++---- 18 files changed, 149 insertions(+), 121 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 6cc09425..f1b402a0 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -539,11 +539,8 @@ cf_new_symbol(byte *c) if (l > SYM_MAX_LEN) cf_error("Symbol too long"); - s = cfg_alloc(sizeof(struct symbol) + l); - s->scope = conf_this_scope; - s->class = SYM_VOID; - s->def = NULL; - s->aux = 0; + s = cfg_allocz(sizeof(struct symbol) + l + 1); + *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, }; strcpy(s->name, c); if (!new_config->sym_hash.data) @@ -574,6 +571,7 @@ cf_find_symbol(struct config *cfg, byte *c) (s = HASH_FIND(cfg->sym_hash, SYM, c, 1))) return s; + /* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */ if (cfg->fallback && cfg->fallback->sym_hash.data && (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1))) @@ -597,6 +595,28 @@ cf_get_symbol(byte *c) return cf_find_symbol(new_config, c) ?: cf_new_symbol(c); } +/** + * cf_localize_symbol - get the local instance of given symbol + * @sym: the symbol to localize + * + * This functions finds the symbol that is local to current scope + * for purposes of cf_define_symbol(). + */ +struct symbol * +cf_localize_symbol(struct symbol *sym) +{ + /* If the symbol type is void, it has been recently allocated just in this scope. */ + if (!sym->class) + return sym; + + /* If the scope is the current, it is already defined in this scope. */ + if (sym->scope == conf_this_scope) + cf_error("Symbol already defined"); + + /* Not allocated here yet, doing it now. */ + return cf_new_symbol(sym->name); +} + struct symbol * cf_default_name(char *template, int *counter) { @@ -616,35 +636,6 @@ cf_default_name(char *template, int *counter) cf_error("Unable to generate default name"); } -/** - * cf_define_symbol - define meaning of a symbol - * @sym: symbol to be defined - * @type: symbol class to assign - * @def: class dependent data - * - * Defines new meaning of a symbol. If the symbol is an undefined - * one (%SYM_VOID), it's just re-defined to the new type. If it's defined - * in different scope, a new symbol in current scope is created and the - * meaning is assigned to it. If it's already defined in the current scope, - * an error is reported via cf_error(). - * - * Result: Pointer to the newly defined symbol. If we are in the top-level - * scope, it's the same @sym as passed to the function. - */ -struct symbol * -cf_define_symbol(struct symbol *sym, int type, void *def) -{ - if (sym->class) - { - if (sym->scope == conf_this_scope) - cf_error("Symbol already defined"); - sym = cf_new_symbol(sym->name); - } - sym->class = type; - sym->def = def; - return sym; -} - static void cf_lex_init_kh(void) { diff --git a/conf/conf.h b/conf/conf.h index 4e3addb3..21d4f1e2 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -105,11 +105,19 @@ extern int (*cf_read_hook)(byte *buf, uint max, int fd); struct symbol { struct symbol *next; struct sym_scope *scope; - int class; - int aux; - uint aux2; - void *def; - char name[1]; + int class; /* SYM_* */ + uint flags; /* SYM_FLAG_* */ + + union { + struct proto_config *proto; /* For SYM_PROTO and SYM_TEMPLATE */ + const struct f_line *function; /* For SYM_FUNCTION */ + const struct filter *filter; /* For SYM_FILTER */ + struct rtable_config *table; /* For SYM_TABLE */ + struct f_dynamic_attr *attribute; /* For SYM_ATTRIBUTE */ + struct f_val *val; /* For SYM_CONSTANT or SYM_VARIABLE */ + }; + + char name[0]; }; struct sym_scope { @@ -134,8 +142,11 @@ struct sym_scope { #define SYM_CONSTANT 0x200 /* 0x200-0x2ff are variable types */ #define SYM_CONSTANT_RANGE SYM_CONSTANT ... (SYM_CONSTANT | 0xff) -#define SYM_TYPE(s) (((struct f_val *) (s)->def)->type) -#define SYM_VAL(s) (((struct f_val *) (s)->def)->val) +#define SYM_TYPE(s) ((s)->val->type) +#define SYM_VAL(s) ((s)->val->val) + +/* Symbol flags */ +#define SYM_FLAG_SAME 0x1 /* For SYM_FUNCTION and SYM_FILTER */ struct include_file_stack { void *buffer; /* Internal lexer state */ @@ -160,7 +171,29 @@ struct symbol *cf_find_symbol(struct config *cfg, byte *c); struct symbol *cf_get_symbol(byte *c); struct symbol *cf_default_name(char *template, int *counter); -struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); +struct symbol *cf_localize_symbol(struct symbol *sym); + +/** + * cf_define_symbol - define meaning of a symbol + * @sym: symbol to be defined + * @type: symbol class to assign + * @def: class dependent data + * + * Defines new meaning of a symbol. If the symbol is an undefined + * one (%SYM_VOID), it's just re-defined to the new type. If it's defined + * in different scope, a new symbol in current scope is created and the + * meaning is assigned to it. If it's already defined in the current scope, + * an error is reported via cf_error(). + * + * Result: Pointer to the newly defined symbol. If we are in the top-level + * scope, it's the same @sym as passed to the function. + */ +#define cf_define_symbol(sym_, type_, var_, def_) ({ \ + struct symbol *sym = cf_localize_symbol(sym_); \ + sym->class = type_; \ + sym->var_ = def_; \ + sym; }) + void cf_push_scope(struct symbol *); void cf_pop_scope(void); char *cf_symbol_class_name(struct symbol *sym); diff --git a/conf/confbase.Y b/conf/confbase.Y index 2195e8fc..62415b4c 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -56,7 +56,8 @@ CF_DECLS struct f_dynamic_attr fda; struct f_static_attr fsa; struct f_lval flv; - struct filter *f; + const struct f_line *fl; + const struct filter *f; struct f_tree *e; struct f_trie *trie; struct f_val v; @@ -130,7 +131,7 @@ definition: DEFINE CF_SYM_VOID '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); - cf_define_symbol($2, SYM_CONSTANT | val->type, val); + cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); } ; diff --git a/filter/config.Y b/filter/config.Y index 488b9ced..b3a04958 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -451,7 +451,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls %type dynamic_attr %type static_attr -%type filter filter_body where_filter +%type filter where_filter +%type filter_body %type lvalue %type type %type ec_kind @@ -467,11 +468,12 @@ CF_GRAMMAR conf: filter_def ; filter_def: - FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } + FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } filter_body { - $2->def = $4; - $4->name = $2->name; - DBG( "We have new filter defined (%s)\n", $2->name ); + struct filter *f = cfg_alloc(sizeof(struct filter)); + *f = (struct filter) { .name = $2->name, .root = $4 }; + $2->filter = f; + cf_pop_scope(); } ; @@ -483,14 +485,14 @@ filter_eval: conf: custom_attr ; custom_attr: ATTRIBUTE type CF_SYM_VOID ';' { - cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda); + cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda); }; conf: bt_test_suite ; bt_test_suite: BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' { struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); - t->fn = $3->def; + t->fn = $3->function; t->fn_name = $3->name; t->dsc = $5; @@ -502,8 +504,8 @@ conf: bt_test_same ; bt_test_same: BT_TEST_SAME '(' CF_SYM_FUNCTION ',' CF_SYM_FUNCTION ',' NUM ')' { struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); - t->fn = $3->def; - t->cmp = $5->def; + t->fn = $3->function; + t->cmp = $5->function; t->result = $7; t->fn_name = $3->name; t->dsc = $5->name; @@ -553,7 +555,7 @@ one_decl: type CF_SYM_VOID { struct f_val * val = cfg_alloc(sizeof(struct f_val)); val->type = T_VOID; - $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); + $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val, val); DBG( "New variable %s type %x\n", $2->name, $1 ); $$ = f_new_inst(FI_SET, NULL, $2); } @@ -578,22 +580,24 @@ declsn: one_decl { $$.inst = $1; $$.count = 1; } filter_body: function_body { - $$ = cfg_alloc(sizeof(struct filter)); - $$->name = NULL; if ($1[0]) { const struct f_inst *inst[2] = { $1[0], $1[1] }; - $$->root = f_postfixify_concat(inst, 2); + $$ = f_postfixify_concat(inst, 2); } else - $$->root = f_postfixify($1[1]); + $$ = f_postfixify($1[1]); } ; filter: CF_SYM_FILTER { - $$ = $1->def; + $$ = $1->filter; + } + | filter_body { + struct filter *f = cfg_alloc(sizeof(struct filter)); + *f = (struct filter) { .root = $1 }; + $$ = f; } - | filter_body ; where_filter: @@ -618,7 +622,7 @@ function_body: conf: function_def ; function_def: FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name ); - $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); + $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope($2); } function_params function_body { const struct f_inst *catlist[4]; @@ -639,9 +643,10 @@ function_def: if ($5[1]) catlist[count++] = $5[1]; - $2->def = f_postfixify_concat(catlist, count); - $2->aux2 = $4.count; - DBG("Hmm, we've got one function here - %s\n", $2->name); + struct f_line *fl = f_postfixify_concat(catlist, count); + fl->args = $4.count; + $2->function = fl; + cf_pop_scope(); } ; @@ -693,7 +698,7 @@ set_atom: } | CF_SYM_CONSTANT { if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); - $$ = *(struct f_val *)($1->def); + $$ = *$1->val; } ; @@ -856,9 +861,9 @@ function_call: ; symbol_value: - CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); } + CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->val); } | CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); } - | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); } + | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *$1->attribute); } ; static_attr: @@ -986,7 +991,7 @@ cmd: $$ = f_new_inst(FI_CONDITION, $2, $4, $6); } | CF_SYM_ATTRIBUTE '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $3, *((struct f_dynamic_attr *) $1->def)); + $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); } | CF_SYM_VARIABLE '=' term ';' { $$ = f_new_inst(FI_SET, $3, $1); diff --git a/filter/decl.m4 b/filter/decl.m4 index 5ac62cbd..3043f4fc 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -188,9 +188,9 @@ const struct symbol *sym; FID_NEW_ARGS , const struct symbol *sym FID_NEW_BODY -what->valp = (what->sym = sym)->def; +what->valp = (what->sym = sym)->val; FID_POSTFIXIFY_BODY -dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def; +dest->items[pos].vp = (dest->items[pos].sym = what->sym)->val; FID_SAME_BODY if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0; FID_DUMP_BODY diff --git a/filter/f-inst.c b/filter/f-inst.c index 4ab46529..6f563873 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -233,7 +233,7 @@ /* IP->Quad implicit conversion */ if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1)) { - *((struct f_val *) sym->def) = (struct f_val) { + *(sym->val) = (struct f_val) { .type = T_QUAD, .val.i = ipa_to_u32(v1.val.ip), }; @@ -241,7 +241,7 @@ } runtime( "Assigning to variable of incompatible type" ); } - *((struct f_val *) sym->def) = v1; + *(sym->val) = v1; } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -709,7 +709,7 @@ /* Postfixify extracts the function body from the symbol */ FID_POSTFIXIFY_BODY - dest->items[pos].lines[0] = what->sym->def; + dest->items[pos].lines[0] = what->sym->function; FID_END /* First push the body on stack */ @@ -727,8 +727,8 @@ for (const struct f_inst *inst = f1; inst; inst = inst->next) count++; - if (count != sym->aux2) - cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); + if (count != sym->function->args) + cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->function->args, count); FID_END /* FIXME: Optimization of function comparison. */ diff --git a/filter/f-inst.h b/filter/f-inst.h index e1d0b675..201be5f8 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -59,6 +59,7 @@ struct f_line_item { /* Line of instructions to be unconditionally executed one after another */ struct f_line { uint len; /* Line length */ + u16 args; /* Function: Args required */ struct f_line_item items[0]; /* The items themselves */ }; @@ -81,8 +82,8 @@ extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); /* Bird Tests */ struct f_bt_test_suite { node n; /* Node in config->tests */ - struct f_line *fn; /* Root of function */ - struct f_line *cmp; /* Compare to this function */ + const struct f_line *fn; /* Root of function */ + const struct f_line *cmp; /* Compare to this function */ const char *fn_name; /* Name of test */ const char *dsc; /* Description */ int result; /* Desired result */ diff --git a/filter/f-util.c b/filter/f-util.c index 82aaa385..85f5d1c4 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -17,8 +17,8 @@ #define P(a,b) ((a<<8) | b) -char * -filter_name(struct filter *filter) +const char * +filter_name(const struct filter *filter) { if (!filter) return "ACCEPT"; diff --git a/filter/filter.c b/filter/filter.c index 29e78204..4249d4ee 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -359,15 +359,14 @@ f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf) /** * filter_same - compare two filters * @new: first filter to be compared - * @old: second filter to be compared, notice that this filter is - * damaged while comparing. + * @old: second filter to be compared * * Returns 1 in case filters are same, otherwise 0. If there are * underlying bugs, it will rather say 0 on same filters than say * 1 on different. */ int -filter_same(struct filter *new, struct filter *old) +filter_same(const struct filter *new, const struct filter *old) { if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */ return 1; diff --git a/filter/filter.h b/filter/filter.h index d03c6438..26faeaa3 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -48,7 +48,7 @@ struct f_val; struct f_line; struct filter { char *name; - struct f_line *root; + const struct f_line *root; }; struct rte; @@ -58,8 +58,8 @@ enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struc uint f_eval_int(const struct f_line *expr); enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf); -char *filter_name(struct filter *filter); -int filter_same(struct filter *new, struct filter *old); +const char *filter_name(const struct filter *filter); +int filter_same(const struct filter *new, const struct filter *old); int f_same(const struct f_line *f1, const struct f_line *f2); #define FILTER_ACCEPT NULL diff --git a/nest/config.Y b/nest/config.Y index fb75c593..c2622ed2 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -179,28 +179,28 @@ proto_name: /* EMPTY */ { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); s->class = this_proto->class; - s->def = this_proto; + s->proto = this_proto; this_proto->name = s->name; } | CF_SYM_VOID { - cf_define_symbol($1, this_proto->class, this_proto); + cf_define_symbol($1, this_proto->class, proto, this_proto); this_proto->name = $1->name; } | FROM sym_proto_or_template { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); s->class = this_proto->class; - s->def = this_proto; + s->proto = this_proto; this_proto->name = s->name; if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); - proto_copy_config(this_proto, $2->def); + proto_copy_config(this_proto, $2->proto); } | CF_SYM_VOID FROM sym_proto_or_template { - cf_define_symbol($1, this_proto->class, this_proto); + cf_define_symbol($1, this_proto->class, proto, this_proto); this_proto->name = $1->name; if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); - proto_copy_config(this_proto, $3->def); + proto_copy_config(this_proto, $3->proto); } ; @@ -256,7 +256,7 @@ channel_end: proto_channel: channel_start channel_opt_list channel_end; -rtable: CF_SYM_TABLE { $$ = $1->def; } ; +rtable: CF_SYM_TABLE { $$ = $1->table; } ; imexport: FILTER filter { $$ = $2; } @@ -544,7 +544,7 @@ r_args: } | r_args TABLE CF_SYM_TABLE { $$ = $1; - rt_show_add_table($$, ((struct rtable_config *)$3->def)->table); + rt_show_add_table($$, $3->table->table); $$->tables_defined_by = RSD_TDB_DIRECT; } | r_args TABLE ALL { @@ -556,7 +556,7 @@ r_args: } | r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel { $$ = $1; - struct proto_config *cf = (void *) $4->def; + struct proto_config *cf = $4->proto; if (!cf->proto) cf_error("%s is not a protocol", $4->name); struct channel *c = proto_find_channel_by_name(cf->proto, $6); if (!c) cf_error("Channel %s.%s not found", $4->name, $6); @@ -587,7 +587,7 @@ r_args: $$->filtered = 1; } | r_args export_mode CF_SYM_PROTO { - struct proto_config *c = (struct proto_config *) $3->def; + struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); if (!c->proto) cf_error("%s is not a protocol", $3->name); @@ -596,7 +596,7 @@ r_args: $$->tables_defined_by = RSD_TDB_INDIRECT; } | r_args export_mode CF_SYM_PROTO '.' r_args_channel { - struct proto_config *c = (struct proto_config *) $3->def; + struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); if (!c->proto) cf_error("%s is not a protocol", $3->name); @@ -606,7 +606,7 @@ r_args: $$->tables_defined_by = RSD_TDB_INDIRECT; } | r_args PROTOCOL CF_SYM_PROTO { - struct proto_config *c = (struct proto_config *) $3->def; + struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->show_protocol) cf_error("Protocol specified twice"); if (!c->proto) cf_error("%s is not a protocol", $3->name); diff --git a/nest/proto.c b/nest/proto.c index d4a333d0..77bf082a 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -977,7 +977,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty { /* Found match, let's check if we can smoothly switch to new configuration */ /* No need to check description */ - nc = sym->def; + nc = sym->proto; nc->proto = p; /* We will try to reconfigure protocol p */ @@ -1905,7 +1905,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t, return; } - cmd(((struct proto_config *)s->def)->proto, arg, 0); + cmd(s->proto->proto, arg, 0); cli_msg(0, ""); } @@ -1948,7 +1948,7 @@ proto_get_named(struct symbol *sym, struct protocol *pr) if (sym->class != SYM_PROTO) cf_error("%s: Not a protocol", sym->name); - p = ((struct proto_config *) sym->def)->proto; + p = sym->proto->proto; if (!p || p->proto != pr) cf_error("%s: Not a %s protocol", sym->name, pr->name); } diff --git a/nest/protocol.h b/nest/protocol.h index 6c04071b..82b46261 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -489,7 +489,7 @@ struct channel_config { struct proto_config *parent; /* Where channel is defined (proto or template) */ struct rtable_config *table; /* Table we're attached to */ - struct filter *in_filter, *out_filter; /* Attached filters */ + const struct filter *in_filter, *out_filter; /* Attached filters */ struct channel_limit rx_limit; /* Limit for receiving routes from protocol (relevant when in_keep_filtered is active) */ struct channel_limit in_limit; /* Limit for importing routes from protocol */ @@ -511,8 +511,8 @@ struct channel { struct proto *proto; struct rtable *table; - struct filter *in_filter; /* Input filter */ - struct filter *out_filter; /* Output filter */ + const struct filter *in_filter; /* Input filter */ + const struct filter *out_filter; /* Output filter */ struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */ struct channel_limit in_limit; /* Input limit */ struct channel_limit out_limit; /* Output limit */ diff --git a/nest/route.h b/nest/route.h index c7ed80ff..7c9f3005 100644 --- a/nest/route.h +++ b/nest/route.h @@ -297,7 +297,7 @@ rte *rte_find(net *net, struct rte_src *src); rte *rte_get_temp(struct rta *); void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); /* rte_update() moved to protocol.h to avoid dependency conflicts */ -int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter); +int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter); rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent); void rt_refresh_begin(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct channel *c); @@ -335,7 +335,7 @@ struct rt_show_data { struct rt_show_data_rtable *last_table; /* Last table in output */ struct fib_iterator fit; /* Iterator over networks in table */ int verbose, tables_defined_by; - struct filter *filter; + const struct filter *filter; struct proto *show_protocol; struct proto *export_protocol; struct channel *export_channel; diff --git a/nest/rt-table.c b/nest/rt-table.c index 6c8e662e..f05bd718 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -398,7 +398,7 @@ static rte * export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent) { struct proto *p = c->proto; - struct filter *filter = c->out_filter; + const struct filter *filter = c->out_filter; struct proto_stats *stats = &c->stats; rte *rt; int v; @@ -1362,7 +1362,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { struct proto *p = c->proto; struct proto_stats *stats = &c->stats; - struct filter *filter = c->in_filter; + const struct filter *filter = c->in_filter; rte *dummy = NULL; net *nn; @@ -1503,7 +1503,7 @@ rte_modify(rte *old) /* Check rtable for best route to given net whether it would be exported do p */ int -rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) +rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter) { net *n = net_find(t, a); rte *rt = n ? n->routes : NULL; @@ -2106,13 +2106,13 @@ rt_new_table(struct symbol *s, uint addr_type) { /* Hack that allows to 'redefine' the master table */ if ((s->class == SYM_TABLE) && - (s->def == new_config->def_tables[addr_type]) && + (s->table == new_config->def_tables[addr_type]) && ((addr_type == NET_IP4) || (addr_type == NET_IP6))) - return s->def; + return s->table; struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config)); - cf_define_symbol(s, SYM_TABLE, c); + cf_define_symbol(s, SYM_TABLE, table, c); c->name = s->name; c->addr_type = addr_type; c->gc_max_ops = 1000; @@ -2171,7 +2171,7 @@ static struct rtable_config * rt_find_table_config(struct config *cf, char *name) { struct symbol *sym = cf_find_symbol(cf, name); - return (sym && (sym->class == SYM_TABLE)) ? sym->def : NULL; + return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL; } /** diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h index b2cec09d..4dfb1b19 100644 --- a/proto/mrt/mrt.h +++ b/proto/mrt/mrt.h @@ -23,7 +23,7 @@ struct mrt_config { struct rtable_config *table_cf; const char *table_expr; - struct filter *filter; + const struct filter *filter; const char *filename; uint period; int always_add_path; @@ -41,7 +41,7 @@ struct mrt_proto { struct mrt_dump_data { const char *table_expr; struct rtable *table_ptr; - struct filter *filter; + const struct filter *filter; char *filename; }; @@ -61,7 +61,7 @@ struct mrt_table_dump_state { /* Configuration information */ const char *table_expr; /* Wildcard for table name (or NULL) */ struct rtable *table_ptr; /* Explicit table (or NULL) */ - struct filter *filter; /* Optional filter */ + const struct filter *filter; /* Optional filter */ const char *filename; /* Filename pattern */ int always_add_path; /* Always use *_ADDPATH message subtypes */ diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index ded5dfe4..24a4168d 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -562,7 +562,7 @@ static struct rte * krt_export_net(struct krt_proto *p, net *net, rte **rt_free) { struct channel *c = p->p.main_channel; - struct filter *filter = c->out_filter; + const struct filter *filter = c->out_filter; rte *rt; if (c->ra_mode == RA_MERGED) diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 0fdd5b34..b0d764fa 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -94,11 +94,9 @@ drop_gid(gid_t gid) static inline void add_num_const(char *name, int val) { - struct symbol *s = cf_get_symbol(name); - s->class = SYM_CONSTANT | T_INT; - s->def = cfg_allocz(sizeof(struct f_val)); - SYM_TYPE(s) = T_INT; - SYM_VAL(s).i = val; + struct f_val *v = cfg_alloc(sizeof(struct f_val)); + *v = (struct f_val) { .type = T_INT, .val.i = val }; + cf_define_symbol(cf_get_symbol(name), SYM_CONSTANT | T_INT, val, v); } /* the code of read_iproute_table() is based on From ea4f55e3dcd472bb6d18c030839597ffd9583462 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 15 Feb 2019 23:59:44 +0100 Subject: [PATCH 33/88] Filter: More cleanup -- customized structures also in struct f_line_item --- filter/config.Y | 8 +-- filter/decl.m4 | 130 ++++++++++++++++++++++--------------------- filter/f-inst.c | 124 ++++++++++++++++++++++++++++------------- filter/f-inst.h | 35 +++--------- filter/filter.c | 5 ++ filter/filter_test.c | 3 +- filter/interpret.m4 | 28 +++++----- filter/test.conf | 6 ++ 8 files changed, 191 insertions(+), 148 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index b3a04958..495a5e5b 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -572,9 +572,9 @@ decls: /* EMPTY */ { $$ = NULL; } /* Declarations that have no ';' at the end. Beware; these are reversed. */ declsn: one_decl { $$.inst = $1; $$.count = 1; } | one_decl ';' declsn { - $$ = $3; - $$.count++; - $$.inst->next = $1; + $1->next = $3.inst; + $$.count = $3.count + 1; + $$.inst = $1; } ; @@ -861,7 +861,7 @@ function_call: ; symbol_value: - CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->val); } + CF_SYM_CONSTANT { $$ = f_new_inst(FI_VARIABLE, $1); } | CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); } | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *$1->attribute); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index 3043f4fc..3033438d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -14,12 +14,11 @@ m4_divert(-1)m4_dnl # 7 dump line item callers # 8 postfixify # 9 same (filter comparator) -# 1 struct f_inst_FI_... -# 2 union in struct f_inst +# 1 union in struct f_inst # 3 constructors # # Per-inst Diversions: -# 101 content of struct f_inst_FI_... +# 101 content of per-inst struct # 102 constructor arguments # 103 constructor body # 104 dump line item content @@ -35,8 +34,8 @@ m4_define(FID_END, `m4_divert(-1)') m4_dnl m4_debugmode(aceflqtx) m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') -m4_define(FID_STRUCT, `FID_ZONE(1, Per-instruction structure)') -m4_define(FID_UNION, `FID_ZONE(2, Union member)') +m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)') +m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)') m4_define(FID_NEW, `FID_ZONE(3, Constructor)') m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') @@ -51,6 +50,7 @@ m4_define(FID_NEW_BODY, `m4_divert(103)') m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') m4_define(FID_POSTFIXIFY_BODY, `m4_divert(105)m4_define([[FID_POSTFIXIFY_BODY_EXISTS]])') m4_define(FID_SAME_BODY, `m4_divert(106)') +m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') @@ -62,12 +62,14 @@ FID_ENUM INST_NAME(), FID_ENUM_STR [INST_NAME()] = "INST_NAME()", -FID_STRUCT -struct f_inst_[[]]INST_NAME() { +FID_INST +struct { m4_undivert(101) -}; -FID_UNION -struct f_inst_[[]]INST_NAME() i_[[]]INST_NAME(); +} i_[[]]INST_NAME(); +FID_LINE +struct { +m4_undivert(107) +} i_[[]]INST_NAME(); FID_NEW struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code m4_undivert(102) @@ -80,8 +82,9 @@ FID_C what_->fi_code = fi_code; what_->lineno = ifs->lino; what_->size = 1; - struct f_inst_[[]]INST_NAME() *what UNUSED = &(what_->i_[[]]INST_NAME()); +#define what (&(what_->i_]]INST_NAME()[[)) m4_undivert(103) +#undef what return what_; } @@ -90,19 +93,23 @@ case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; FID_DUMP m4_ifdef([[FID_DUMP_BODY_EXISTS]], -[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item, const int indent)]] -, +[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]], [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) m4_undefine([[FID_DUMP_BODY_EXISTS]]) { +#define item (&(item_->i_]]INST_NAME()[[)) m4_undivert(104) +#undef item } FID_ALL FID_POSTFIXIFY case INST_NAME(): { -m4_ifdef([[FID_POSTFIXIFY_BODY_EXISTS]], [[const struct f_inst_]]INST_NAME()[[ *what = &(what_->i_]]INST_NAME()[[);]], [[]]) +#define what (&(what_->i_]]INST_NAME()[[)) +#define item (&(dest->items[pos].i_]]INST_NAME()[[)) m4_undivert(105) +#undef what +#undef item dest->items[pos].fi_code = what_->fi_code; dest->items[pos].lineno = what_->lineno; break; @@ -111,7 +118,11 @@ m4_undefine([[FID_POSTFIXIFY_BODY_EXISTS]]) FID_SAME case INST_NAME(): +#define f1 (&(f1_->i_]]INST_NAME()[[)) +#define f2 (&(f2_->i_]]INST_NAME()[[)) m4_undivert(106) +#undef f1 +#undef f2 break; FID_END @@ -127,6 +138,8 @@ m4_dnl comparator for same m4_dnl dump format string m4_dnl dump format args m4_define(FID_MEMBER, `m4_dnl +FID_LINE_IN +$1 $2; FID_STRUCT_IN $1 $2; FID_NEW_ARGS @@ -135,7 +148,7 @@ FID_NEW_BODY what->$2 = $2; m4_ifelse($3,,,[[ FID_POSTFIXIFY_BODY -dest->items[pos].$3 = what->$2; +item->$3 = what->$2; ]]) m4_ifelse($4,,,[[ FID_SAME_BODY @@ -147,55 +160,37 @@ debug("%s$5\n", INDENT, $6); ]]) FID_END') -m4_define(ARG, `FID_MEMBER(const struct f_inst *, f$1,,,,) +m4_define(ARG, ` +FID_STRUCT_IN +const struct f_inst * f$1; +FID_NEW_ARGS +, const struct f_inst * f$1 FID_NEW_BODY +what->f$1 = f$1; for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_POSTFIXIFY_BODY pos = postfixify(dest, what->f$1, pos); FID_END') -m4_define(ARG_ANY, `FID_MEMBER(const struct f_inst *, f$1,,,,) +m4_define(ARG_ANY, `ARG($@)') +m4_define(LINE, ` +FID_LINE_IN +const struct f_line * fl$1; +FID_STRUCT_IN +const struct f_inst * f$1; +FID_NEW_ARGS +, const struct f_inst * f$1 FID_NEW_BODY -for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; -FID_POSTFIXIFY_BODY -pos = postfixify(dest, what->f$1, pos); -FID_END') -m4_define(LINE, `FID_MEMBER(const struct f_inst *, f$1,,[[!f_same(f1->lines[$2], f2->lines[$2])]],,) +what->f$1 = f$1; FID_DUMP_BODY -f_dump_line(item->lines[$2], indent + 1); +f_dump_line(item->fl$1, indent + 1); FID_POSTFIXIFY_BODY -dest->items[pos].lines[$2] = f_postfixify(what->f$1); -FID_END') -m4_define(LINEP, `FID_STRUCT_IN -const struct f_line *fl$1; -FID_DUMP_BODY -f_dump_line(item->lines[$2], indent + 1) -FID_POSTFIXIFY_BODY -dest->items[pos].lines[$2] = what->fl$1; +item->fl$1 = f_postfixify(what->f$1); FID_SAME_BODY -if (!f_same(f1->lines[$2], f2->lines[$2])) return 0; +if (!f_same(f1->fl$1, f2->fl$1)) return 0; FID_END') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') -m4_define(VALI, `FID_MEMBER(struct f_val, vali, val, [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val))') -m4_define(VALP, `FID_MEMBER(const struct f_val *, valp,, [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val)) -FID_POSTFIXIFY_BODY -dest->items[pos].val = *(what->valp); -FID_END') -m4_define(VAR, `m4_dnl -FID_STRUCT_IN -const struct f_val *valp; -const struct symbol *sym; -FID_NEW_ARGS -, const struct symbol *sym -FID_NEW_BODY -what->valp = (what->sym = sym)->val; -FID_POSTFIXIFY_BODY -dest->items[pos].vp = (dest->items[pos].sym = what->sym)->val; -FID_SAME_BODY -if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0; -FID_DUMP_BODY -debug("%svariable %s with value %s\n", INDENT, item->sym->name, val_dump(item->vp)); -FID_END') +m4_define(VAL, `FID_MEMBER(struct f_val $1, val, val m4_ifelse($1,,,[0]), [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val))') m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret))') m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs))') m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') @@ -240,11 +235,10 @@ FID_WR_PUT(3) /* Line dumpers */ #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) static const char f_dump_line_indent_str[] = " "; -void f_dump_line(const struct f_line *dest, int indent); FID_WR_PUT(6) -void f_dump_line(const struct f_line *dest, int indent) +void f_dump_line(const struct f_line *dest, uint indent) { if (!dest) { debug("%sNo filter line (NULL)\n", INDENT); @@ -305,17 +299,19 @@ f_same(const struct f_line *fl1, const struct f_line *fl2) if (fl1->len != fl2->len) return 0; for (uint i=0; ilen; i++) { -#define f1 (&(fl1->items[i])) -#define f2 (&(fl2->items[i])) - if (f1->fi_code != f2->fi_code) +#define f1_ (&(fl1->items[i])) +#define f2_ (&(fl2->items[i])) + if (f1_->fi_code != f2_->fi_code) return 0; - if (f1->flags != f2->flags) + if (f1_->flags != f2_->flags) return 0; - switch(f1->fi_code) { + switch(f1_->fi_code) { FID_WR_PUT(9) } } +#undef f1_ +#undef f2_ return 1; } @@ -324,16 +320,24 @@ FID_WR_DIRECT(900,H) /* Filter instruction codes */ enum f_instruction_code { FID_WR_PUT(4) -}; - -/* Per-instruction structures */ -FID_WR_PUT(1) +} PACKED; +/* Filter instruction structure for config */ struct f_inst { const struct f_inst *next; /* Next instruction */ enum f_instruction_code fi_code; /* Instruction code */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ + union { + FID_WR_PUT(1) + }; +}; + +/* Filter line item */ +struct f_line_item { + enum f_instruction_code fi_code; /* What to do */ + enum f_instruction_flags flags; /* Flags, instruction-specific */ + uint lineno; /* Where */ union { FID_WR_PUT(2) }; diff --git a/filter/f-inst.c b/filter/f-inst.c index 6f563873..128b9e54 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -119,13 +119,12 @@ what->count = len; FID_END - if (vstk.cnt < what->count) /* TODO: make this check systematic */ - runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count); + if (vstk.cnt < whati->count) /* TODO: make this check systematic */ + runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); - struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item)); - for (uint i=0; icount; i++) { -//#define pv vstk.val[vstk.cnt-i-1] -#define pv vstk.val[vstk.cnt - what->count + i] + struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); + for (uint i=0; icount; i++) { +#define pv vstk.val[vstk.cnt - whati->count + i] switch (pv.type) { case T_PATH_MASK_ITEM: pm->item[i] = pv.val.pmi; @@ -141,8 +140,8 @@ } } - vstk.cnt -= what->count; - pm->len = what->count; + vstk.cnt -= whati->count; + pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); } @@ -246,15 +245,53 @@ /* some constants have value in a[1], some in *a[0].p, strange. */ INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */ - VALI; // res = what->val; + FID_LINE_IN + struct f_val val; + FID_STRUCT_IN + struct f_val val; + FID_NEW_ARGS + , const struct f_val val + FID_NEW_BODY + what->val = val; + FID_POSTFIXIFY_BODY + item->val = what->val; + FID_SAME_BODY + if (!val_same(&(f1->val), &(f2->val))) return 0; + FID_DUMP_BODY + debug("%svalue %s\n", INDENT, val_dump(&item->val)); + FID_END + + res = whati->val; RESULT_OK; } INST(FI_VARIABLE, 0, 1) { - VAR; - RESULT_OK; - } - INST(FI_CONSTANT_INDIRECT, 0, 1) { - VALP; + FID_STRUCT_IN + const struct symbol *sym; + FID_LINE_IN + const struct symbol *sym; + const struct f_val *valp; + FID_NEW_ARGS + , const struct symbol *sym + FID_NEW_BODY + what->sym = sym; + FID_POSTFIXIFY_BODY + item->valp = (item->sym = what->sym)->val; + FID_SAME_BODY + if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0; + FID_DUMP_BODY + switch (item->sym->class) { + case SYM_CONSTANT_RANGE: + debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); + break; + case SYM_VARIABLE_RANGE: + debug("%svariable %s with current value %s\n", INDENT, item->sym->name, val_dump(item->valp)); + break; + default: + bug("Symbol %s of type %d doesn't reference a value", item->sym->name, item->sym->class); + } + FID_END + + res = *whati->valp; RESULT_OK; } INST(FI_PRINT, 1, 0) { @@ -702,36 +739,48 @@ } INST(FI_CALL, 0, 1) { - /* Do not use the symbol on execution */ - if (0) { - UNUSED SYMBOL; - } - - /* Postfixify extracts the function body from the symbol */ - FID_POSTFIXIFY_BODY - dest->items[pos].lines[0] = what->sym->function; - FID_END - - /* First push the body on stack */ - LINEX(what->lines[0]); - curline.emask |= FE_RETURN; - - /* Then push the arguments */ - LINE(1,1); - + FID_LINE_IN + const struct f_line *args; + const struct f_line *body; + struct symbol *sym; + FID_STRUCT_IN + struct symbol *sym; + const struct f_inst *args; + FID_NEW_ARGS + , struct symbol * sym + , const struct f_inst *args FID_NEW_BODY if (sym->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); uint count = 0; - for (const struct f_inst *inst = f1; inst; inst = inst->next) + for (const struct f_inst *inst = args; inst; inst = inst->next) count++; if (count != sym->function->args) cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->function->args, count); + + what->sym = sym; + what->args = args; + FID_DUMP_BODY + debug("%scalling %s with following args\n", INDENT, item->sym->name); + f_dump_line(item->args, indent + 1); + FID_POSTFIXIFY_BODY + item->args = f_postfixify(what->args); + item->body = (item->sym = what->sym)->function; + FID_SAME_BODY + /* To be done better */ + if (strcmp(f1->sym->name, f2->sym->name)) return 0; + if (!f_same(f1->args, f2->args)) return 0; + if (!f_same(f1->body, f2->body)) return 0; FID_END - /* FIXME: Optimization of function comparison. */ + /* First push the body on stack */ + LINEX(whati->body); + curline.emask |= FE_RETURN; + + /* Then push the arguments */ + LINEX(whati->args); } INST(FI_DROP_RESULT, 1, 0) { @@ -741,18 +790,17 @@ INST(FI_SWITCH, 1, 0) { ARG_ANY(1); TREE; - const struct f_tree *t = find_tree(what->tree, &v1); - if (!t) { + if (!tree) { v1.type = T_VOID; - t = find_tree(what->tree, &v1); - if (!t) { + tree = find_tree(tree, &v1); + if (!tree) { debug( "No else statement?\n"); break; } } /* It is actually possible to have t->data NULL */ - LINEX(t->data); + LINEX(tree->data); } INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */ diff --git a/filter/f-inst.h b/filter/f-inst.h index 201be5f8..5b397a5d 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -15,6 +15,11 @@ #include "filter/filter.h" #include "filter/data.h" +/* Flags for instructions */ +enum f_instruction_flags { + FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ +} PACKED; + /* Include generated filter instruction declarations */ #include "filter/inst-gen.h" @@ -25,37 +30,9 @@ const char *f_instruction_name(enum f_instruction_code fi); struct f_inst *f_clear_local_vars(struct f_inst *decls); -/* Flags for instructions */ -enum f_instruction_flags { - FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ -}; - /* Filter structures for execution */ struct f_line; -/* The single instruction item */ -struct f_line_item { - enum f_instruction_code fi_code; /* What to do */ - enum f_instruction_flags flags; /* Flags, instruction-specific */ - uint lineno; /* Where */ - union { - struct { - const struct f_val *vp; - const struct symbol *sym; - }; - struct f_val val; - const struct f_line *lines[2]; - enum filter_return fret; - struct f_static_attr sa; - struct f_dynamic_attr da; - enum ec_subtype ecs; - const char *s; - const struct f_tree *tree; - const struct rtable_config *rtc; - uint count; - }; /* Additional instruction data */ -}; - /* Line of instructions to be unconditionally executed one after another */ struct f_line { uint len; /* Line length */ @@ -68,6 +45,8 @@ struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint coun static inline struct f_line *f_postfixify(const struct f_inst *root) { return f_postfixify_concat(&root, 1); } +void f_dump_line(const struct f_line *, uint indent); + struct filter *f_new_where(const struct f_inst *); static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ diff --git a/filter/filter.c b/filter/filter.c index 4249d4ee..8db5119b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -167,6 +167,11 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define curline estk.item[estk.cnt-1] +#if DEBUGGING + debug("Interpreting line."); + f_dump_line(line, 1); +#endif + while (estk.cnt > 0) { while (curline.pos < curline.line->len) { const struct f_line_item *what = &(curline.line->items[curline.pos++]); diff --git a/filter/filter_test.c b/filter/filter_test.c index d83e8a8b..d0dd281a 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -74,7 +74,8 @@ bt_assert_filter(int result, const struct f_line_item *assert) bt_suit_case_result = 0; } - bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, assert->s); + bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", + assert->lineno, assert->i_FI_ASSERT.s); } int diff --git a/filter/interpret.m4 b/filter/interpret.m4 index eb368b41..ea91e74e 100644 --- a/filter/interpret.m4 +++ b/filter/interpret.m4 @@ -13,8 +13,10 @@ m4_define(DNL, `m4_dnl') m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ m4_divert(1) case INST_NAME(): +#define whati (&(what->i_]]INST_NAME()[[)) m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]]) m4_undivert(2) +#undef whati break; m4_divert(-1) ]])') @@ -36,37 +38,35 @@ m4_define(LINEX, `do { } while (0)') m4_define(LINE, `do { - if (what->lines[$2]) { + if (whati->fl$1) { estk.item[estk.cnt].pos = 0; - estk.item[estk.cnt].line = what->lines[$2]; + estk.item[estk.cnt].line = whati->fl$1; estk.item[estk.cnt].ventry = vstk.cnt; estk.item[estk.cnt].emask = 0; estk.cnt++; } } while (0)') -m4_define(LINEP, LINE($1, $2)) - m4_define(ARG_ANY, `') -m4_define(SYMBOL, `const struct symbol *sym = what->sym') +m4_define(SYMBOL, `const struct symbol *sym = whati->sym') -m4_define(VALI, `res = what->val') -m4_define(VALP, `res = what->val') -m4_define(VAR, `res = *what->vp') -m4_define(FRET, `enum filter_return fret = what->fret') -m4_define(ECS, `enum ec_subtype ecs = what->ecs') -m4_define(RTC, `struct rtable *table = what->rtc->table') -m4_define(STATIC_ATTR, `struct f_static_attr sa = what->sa') -m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da') -m4_define(TREE, `') +m4_define(FRET, `enum filter_return fret = whati->fret') +m4_define(ECS, `enum ec_subtype ecs = whati->ecs') +m4_define(RTC, `struct rtable *table = whati->rtc->table') +m4_define(STATIC_ATTR, `struct f_static_attr sa = whati->sa') +m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = whati->da') +m4_define(TREE, `const struct f_tree *tree = whati->tree') m4_define(STRING, `') m4_define(COUNT, `') m4_define(SAME, `') m4_define(FID_STRUCT_IN, `m4_divert(-1)') +m4_define(FID_LINE_IN, `m4_divert(-1)') m4_define(FID_NEW_ARGS, `m4_divert(-1)') m4_define(FID_NEW_BODY, `m4_divert(-1)') m4_define(FID_POSTFIXIFY_BODY, `m4_divert(-1)') +m4_define(FID_SAME_BODY, `m4_divert(-1)') +m4_define(FID_DUMP_BODY, `m4_divert(-1)') m4_define(FID_END, `m4_divert(2)') m4_m4wrap(` diff --git a/filter/test.conf b/filter/test.conf index 89215d1c..dc47eb7d 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -1117,6 +1117,11 @@ int i; return 0; } +function callmeagain(int a; int b; int c) +{ + return a + b + c; +} + function fifteen() { return 15; @@ -1133,6 +1138,7 @@ function t_call_function() bt_assert(callme(3, 2) = 6); bt_assert(callme(4, 4) = 16); bt_assert(callme(7, 2) = 14); + bt_assert(callmeagain(1, 2, 3) = 6); } bt_test_suite(t_call_function, "Testing calling functions"); From d4bf74816faf9955297f93f8bb6973c1f600dbe2 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 18 Feb 2019 14:56:10 +0100 Subject: [PATCH 34/88] GDB: Added more pretty printers for filters --- bird-gdb.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/bird-gdb.py b/bird-gdb.py index e91a633f..a85ef8c6 100644 --- a/bird-gdb.py +++ b/bird-gdb.py @@ -59,6 +59,19 @@ class BIRDFValPrinter(BIRDPrinter): def display_hint(self): return "map" +class BIRDFValStackPrinter(BIRDPrinter): + "Print BIRD's struct f_val_stack" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_val_stack" + + def to_string(self): + cnt = self.val['cnt'] + return ("Value stack (%(cnt)d):\n\t" % { "cnt": cnt }) + \ + "\n\t".join([ (".val[%(n) 3d] = " % { "n": n}) + str(self.val['val'][n]) for n in range(cnt-1, -1, -1) ]) + + def display_hint(self): + return "map" + class BIRDFInstPrinter(BIRDPrinter): "Print BIRD's struct f_inst" typeCode = gdb.TYPE_CODE_STRUCT @@ -68,16 +81,72 @@ class BIRDFInstPrinter(BIRDPrinter): code = self.val['fi_code'] if str(code) == "FI_NOP": return str(code) + ": " + str(self.val.cast(gdb.lookup_type("const char [%(siz)d]" % { "siz": self.val.type.sizeof }))) - return str(code) + ": " + str(self.val['i_' + str(code)]) + return "%(code)s:\t%(lineno) 6dL\t%(size)6dS\tnext = %(next)s: .i_%(code)s = %(union)s" % { + "code": str(code), + "lineno": self.val['lineno'], + "size": self.val['size'], + "next": str(self.val['next']), + "union": str(self.val['i_' + str(code)]) + } # def children(self): # children iterator def display_hint(self): return "map" +class BIRDFLineItemPrinter(BIRDPrinter): + "Print BIRD's struct f_line_item" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_line_item" + + def to_string(self): + code = self.val['fi_code'] + if str(code) == "FI_NOP": + return str(code) + ": " + str(self.val.cast(gdb.lookup_type("const char [%(siz)d]" % { "siz": self.val.type.sizeof }))) + return "%(code)s:\t%(lineno) 6dL\t%(flags)2dF: .i_%(code)s = %(union)s" % { + "code": str(code), + "lineno": self.val['lineno'], + "flags": self.val['flags'], + "union": str(self.val['i_' + str(code)]) + } + +class BIRDFLinePrinter(BIRDPrinter): + "Print BIRD's struct f_line" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_line" + + def to_string(self): + cnt = self.val['len'] + return ("FLine (%(cnt)d, args=%(args)d): " % { "cnt": cnt, "args" : self.val['args'] } + \ + ", ".join([ + ".items[%(n) 3d] = %(code)s" % { + "n": n, + "code": str(self.val['items'][n]['fi_code']), + } if n % 8 == 0 else str(self.val['items'][n]['fi_code']) for n in range(cnt)])) + + +class BIRDFExecStackPrinter(BIRDPrinter): + "Print BIRD's struct f_exec_stack" + typeCode = gdb.TYPE_CODE_STRUCT + typeTag = "f_exec_stack" + + def to_string(self): + cnt = self.val['cnt'] + return ("Exec stack (%(cnt)d):\n\t" % { "cnt": cnt }) + \ + "\n\t".join([ ".item[%(n) 3d] = %(retflag)d V%(ventry) 3d P%(pos) 4d %(line)s" % { + "retflag": self.val['item'][n]['emask'], + "ventry": self.val['item'][n]['ventry'], + "pos": self.val['item'][n]['pos'], + "line": str(self.val['item'][n]['line'].dereference()), + "n": n + } for n in range(cnt-1, -1, -1) ]) def register_printers(objfile): objfile.pretty_printers.append(BIRDFInstPrinter.lookup) objfile.pretty_printers.append(BIRDFValPrinter.lookup) + objfile.pretty_printers.append(BIRDFValStackPrinter.lookup) + objfile.pretty_printers.append(BIRDFLineItemPrinter.lookup) + objfile.pretty_printers.append(BIRDFLinePrinter.lookup) + objfile.pretty_printers.append(BIRDFExecStackPrinter.lookup) register_printers(gdb.current_objfile()) From d348a916f57cb0ac390718295624dd9a1cf2d32a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 18 Feb 2019 14:56:49 +0100 Subject: [PATCH 35/88] Test: Added -d flag to die directly after first error. --- test/birdtest.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/birdtest.c b/test/birdtest.c index 347f79b9..b5ee48c7 100644 --- a/test/birdtest.c +++ b/test/birdtest.c @@ -31,6 +31,7 @@ static const char *request; static int list_tests; static int do_core; +static int do_die; static int no_fork; static int no_timeout; static int is_terminal; /* Whether stdout is a live terminal or pipe redirect */ @@ -67,7 +68,7 @@ bt_init(int argc, char *argv[]) bt_test_id = NULL; is_terminal = isatty(fileno(stdout)); - while ((c = getopt(argc, argv, "lcftv")) >= 0) + while ((c = getopt(argc, argv, "lcdftv")) >= 0) switch (c) { case 'l': @@ -78,6 +79,10 @@ bt_init(int argc, char *argv[]) do_core = 1; break; + case 'd': + do_die = 1; + break; + case 'f': no_fork = 1; break; @@ -111,10 +116,11 @@ bt_init(int argc, char *argv[]) return; usage: - printf("Usage: %s [-l] [-c] [-f] [-t] [-vvv] []\n", argv[0]); + printf("Usage: %s [-l] [-c] [-d] [-f] [-t] [-vvv] []\n", argv[0]); printf("Options: \n"); printf(" -l List all test suite names and descriptions \n"); printf(" -c Force unlimit core dumps (needs root privileges) \n"); + printf(" -d Die on first failed test case \n"); printf(" -f No forking \n"); printf(" -t No timeout limit \n"); printf(" -v More verbosity, maximum is 3 -vvv \n"); @@ -223,6 +229,9 @@ bt_log_result(int result, const char *fmt, va_list argptr) result_str = is_terminal ? BT_PROMPT_FAIL : BT_PROMPT_FAIL_NO_COLOR; printf("%s\n", result_str); + + if (do_die && !result) + abort(); } /** From 32793ab685b047b553d6f7afc23b3245e8850e4a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 18 Feb 2019 14:57:15 +0100 Subject: [PATCH 36/88] Filter: Fixed bugs in FI_CALL and FI_SWITCH --- conf/confbase.Y | 1 - filter/config.Y | 29 ++++++++++++++++------------- filter/f-inst.c | 9 +++++---- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index 62415b4c..dcc92365 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -50,7 +50,6 @@ CF_DECLS struct channel_config *cc; struct f_inst *x; struct f_inst *xp[2]; - struct { struct f_inst *inst; uint count; } xc; enum filter_return fret; enum ec_subtype ecs; struct f_dynamic_attr fda; diff --git a/filter/config.Y b/filter/config.Y index 495a5e5b..5ec226f0 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -446,8 +446,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc THEN %nonassoc ELSE -%type function_params declsn -%type cmds_int function_body +%type cmds_int function_body declsn function_params %type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls %type dynamic_attr %type static_attr @@ -561,7 +560,7 @@ one_decl: } ; -/* Decls with ';' at the end */ +/* Decls with ';' at the end. Beware; these are reversed. */ decls: /* EMPTY */ { $$ = NULL; } | one_decl ';' decls { $$ = $1; @@ -569,12 +568,12 @@ decls: /* EMPTY */ { $$ = NULL; } } ; -/* Declarations that have no ';' at the end. Beware; these are reversed. */ -declsn: one_decl { $$.inst = $1; $$.count = 1; } +/* Declarations that have no ';' at the end. */ +declsn: one_decl { $$[0] = $$[1] = $1; } | one_decl ';' declsn { - $1->next = $3.inst; - $$.count = $3.count + 1; - $$.inst = $1; + $3[1]->next = $1; + $$[1] = $3[1] = $1; + $$[0] = $3[0]; } ; @@ -608,8 +607,8 @@ where_filter: ; function_params: - '(' declsn ')' { $$ = $2; } - | '(' ')' { $$.inst = NULL; $$.count = 0; } + '(' declsn ')' { $$[0] = $2[0]; $$[1] = $2[1]; } + | '(' ')' { $$[0] = $$[1] = NULL; } ; function_body: @@ -629,8 +628,8 @@ function_def: uint count = 0; /* Argument setters */ - if ($4.inst) - catlist[count++] = $4.inst; + if ($4[0]) + catlist[count++] = $4[0]; /* Local var clearers */ if ($5[0]) @@ -644,7 +643,11 @@ function_def: catlist[count++] = $5[1]; struct f_line *fl = f_postfixify_concat(catlist, count); - fl->args = $4.count; + + fl->args = 0; + for (const struct f_inst *arg = $4[0]; arg; arg = arg->next) + fl->args++; + $2->function = fl; cf_pop_scope(); diff --git a/filter/f-inst.c b/filter/f-inst.c index 128b9e54..27a4ab88 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -790,17 +790,18 @@ INST(FI_SWITCH, 1, 0) { ARG_ANY(1); TREE; - if (!tree) { + const struct f_tree *t = find_tree(tree, &v1); + if (!t) { v1.type = T_VOID; - tree = find_tree(tree, &v1); - if (!tree) { + t = find_tree(tree, &v1); + if (!t) { debug( "No else statement?\n"); break; } } /* It is actually possible to have t->data NULL */ - LINEX(tree->data); + LINEX(t->data); } INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */ From d1039926f5ee5a4e0442919474f16f3c93385cc9 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 19 Feb 2019 12:34:16 +0100 Subject: [PATCH 37/88] Filter: Interpreter merged into the common m4 generator. The config-time partial evaluation of constant expressions in filters is nearby. --- filter/Makefile | 10 ++--- filter/decl.m4 | 91 +++++++++++++++++++++++++++++++++++---------- filter/f-inst.c | 12 +++--- filter/filter.c | 2 +- filter/interpret.m4 | 80 --------------------------------------- filter/test.conf | 6 +++ 6 files changed, 90 insertions(+), 111 deletions(-) delete mode 100644 filter/interpret.m4 diff --git a/filter/Makefile b/filter/Makefile index 65602ea8..9562a2ee 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -7,19 +7,19 @@ $(conf-y-targets) $(conf-lex-targets) $(src-o-files): $(o)inst-gen.h M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) -$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp - $(M4) $(M4FLAGS_FILTERS) -P $^ >$@ - $(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=H -P $^ >$@ $(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@ -$(o)filter.o: $(o)f-inst-interpret.c $(o)inst-gen.h +$(o)inst-interpret.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp + $(M4) $(M4FLAGS_FILTERS) -DTARGET=I -P $^ >$@ + +$(o)filter.o: $(o)inst-interpret.c $(o)inst-gen.h tests_src := tree_test.c filter_test.c trie_test.c tests_targets := $(tests_targets) $(tests-target-files) tests_objs := $(tests_objs) $(src-o-files) -$(call clean,inst-gen.h inst-gen.c) +$(call clean,inst-gen.h inst-gen.c inst-interpret.c) diff --git a/filter/decl.m4 b/filter/decl.m4 index 3033438d..bdd59f20 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -16,6 +16,7 @@ m4_divert(-1)m4_dnl # 9 same (filter comparator) # 1 union in struct f_inst # 3 constructors +# 10 interpreter # # Per-inst Diversions: # 101 content of per-inst struct @@ -24,7 +25,10 @@ m4_divert(-1)m4_dnl # 104 dump line item content # 105 postfixify body # 106 comparator body +# 107 struct f_line_item content +# 108 interpreter body # +# Diversions for TARGET=I: 7xx # Diversions for TARGET=C: 8xx # Diversions for TARGET=H: 9xx @@ -43,6 +47,7 @@ m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') m4_define(FID_POSTFIXIFY, `FID_ZONE(8, Postfixify)') m4_define(FID_SAME, `FID_ZONE(9, Comparison)') +m4_define(FID_INTERPRET, `FID_ZONE(10, Interpret)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') @@ -51,10 +56,14 @@ m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') m4_define(FID_POSTFIXIFY_BODY, `m4_divert(105)m4_define([[FID_POSTFIXIFY_BODY_EXISTS]])') m4_define(FID_SAME_BODY, `m4_divert(106)') m4_define(FID_LINE_IN, `m4_divert(107)') +m4_define(FID_INTERPRET_BODY, `m4_divert(108)') -m4_define(FID_ALL, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') -m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') -m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') +m4_define(FID_ALL, `FID_INTERPRET_BODY'); + +m4_define(FID_ALL_TARGETS, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') +m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') +m4_define(FID_I, `m4_ifelse(TARGET, [[I]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') +m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ @@ -101,7 +110,7 @@ m4_undefine([[FID_DUMP_BODY_EXISTS]]) m4_undivert(104) #undef item } -FID_ALL +FID_ALL_TARGETS FID_POSTFIXIFY case INST_NAME(): { @@ -125,10 +134,23 @@ m4_undivert(106) #undef f2 break; +FID_INTERPRET +case INST_NAME(): +#define whati (&(what->i_]]INST_NAME()[[)) +m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]]) +m4_undivert(108) +#undef whati +break; + FID_END ]])') -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])') +m4_define(INST, `m4_dnl +INST_FLUSH()m4_dnl +m4_define([[INST_NAME]], [[$1]])m4_dnl +m4_define([[INST_INVAL]], [[$2]])m4_dnl +FID_ALL() m4_dnl +') m4_dnl FID_MEMBER call: m4_dnl type @@ -137,6 +159,7 @@ m4_dnl name in f_line_item m4_dnl comparator for same m4_dnl dump format string m4_dnl dump format args +m4_dnl interpreter body m4_define(FID_MEMBER, `m4_dnl FID_LINE_IN $1 $2; @@ -158,9 +181,13 @@ m4_ifelse($5,,,[[ FID_DUMP_BODY debug("%s$5\n", INDENT, $6); ]]) -FID_END') +m4_ifelse($7,,,[[ +FID_INTERPRET_BODY +$7 +]]) +FID_ALL') -m4_define(ARG, ` +m4_define(ARG_ANY, ` FID_STRUCT_IN const struct f_inst * f$1; FID_NEW_ARGS @@ -169,9 +196,24 @@ FID_NEW_BODY what->f$1 = f$1; for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; FID_POSTFIXIFY_BODY -pos = postfixify(dest, what->f$1, pos); -FID_END') -m4_define(ARG_ANY, `ARG($@)') +pos = postfixify(dest, what->f$1, pos);m4_dnl +FID_ALL()') + +m4_define(ARG, `ARG_ANY($1) +FID_INTERPRET_BODY +if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl +FID_ALL()') + +m4_define(LINEX, `FID_INTERPRET_BODY +do { + estk.item[estk.cnt].pos = 0; + estk.item[estk.cnt].line = $1; + estk.item[estk.cnt].ventry = vstk.cnt; + estk.item[estk.cnt].emask = 0; + estk.cnt++; +} while (0)m4_dnl +FID_ALL()') + m4_define(LINE, ` FID_LINE_IN const struct f_line * fl$1; @@ -187,17 +229,26 @@ FID_POSTFIXIFY_BODY item->fl$1 = f_postfixify(what->f$1); FID_SAME_BODY if (!f_same(f1->fl$1, f2->fl$1)) return 0; -FID_END') +FID_INTERPRET_BODY +do { if (whati->fl$1) { + LINEX(whati->fl$1); +} } while(0)m4_dnl +FID_ALL()') + +m4_define(RESULT_OK, `FID_INTERPRET_BODY()vstk.cnt++FID_ALL()') +m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') +m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') + m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, -[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') -m4_define(VAL, `FID_MEMBER(struct f_val $1, val, val m4_ifelse($1,,,[0]), [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val))') -m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret))') -m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs))') -m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') -m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code)') +[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') +m4_define(VAL, `FID_MEMBER(struct f_val $1, val, val m4_ifelse($1,,,[0]), [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val),)') +m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret), enum filter_return fret = whati->fret)') +m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->ecs)') +m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name, struct rtable *table = whati->rtc->table)') +m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code,,, struct f_static_attr sa = whati->sa)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code,,, struct f_dynamic_attr da = whati->da)') m4_define(COUNT, `FID_MEMBER(uint, count, count, f1->count != f2->count, number %u, item->count)') -m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree)') +m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree, const struct f_tree *tree = whati->tree)') m4_define(STRING, `FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s)') m4_define(FID_WR_PUT_LIST) @@ -210,6 +261,8 @@ m4_define(FID_WR_DIRECT, `m4_define([[FID_WR_CUR_DIRECT]],$1)m4_ifelse(TARGET,[[ m4_dnl m4_define(FID_WR_CUR_DIRECT,m4_ifelse(TARGET,`C',800,TARGET,`H',900,m4_errprint(`Bad TARGET: 'TARGET)m4_m4exit(1))) m4_changequote([[,]]) +FID_WR_DIRECT(700,I) +FID_WR_PUT(10) FID_WR_DIRECT(800,C) #include "nest/bird.h" #include "filter/filter.h" diff --git a/filter/f-inst.c b/filter/f-inst.c index 27a4ab88..8505534a 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -117,7 +117,7 @@ dyn++; what->count = len; - FID_END + FID_ALL if (vstk.cnt < whati->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); @@ -259,7 +259,7 @@ if (!val_same(&(f1->val), &(f2->val))) return 0; FID_DUMP_BODY debug("%svalue %s\n", INDENT, val_dump(&item->val)); - FID_END + FID_ALL res = whati->val; RESULT_OK; @@ -289,7 +289,7 @@ default: bug("Symbol %s of type %d doesn't reference a value", item->sym->name, item->sym->class); } - FID_END + FID_ALL res = *whati->valp; RESULT_OK; @@ -309,7 +309,7 @@ FID_POSTFIXIFY_BODY { uint opos = pos; - FID_END + FID_ALL ARG_ANY(1); @@ -317,7 +317,7 @@ if (opos < pos) dest->items[pos].flags |= FIF_PRINTED; } - FID_END + FID_ALL FRET(2); @@ -773,7 +773,7 @@ if (strcmp(f1->sym->name, f2->sym->name)) return 0; if (!f_same(f1->args, f2->args)) return 0; if (!f_same(f1->body, f2->body)) return 0; - FID_END + FID_ALL /* First push the body on stack */ LINEX(whati->body); diff --git a/filter/filter.c b/filter/filter.c index 8db5119b..ee5d5426 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -192,7 +192,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) -#include "filter/f-inst-interpret.c" +#include "filter/inst-interpret.c" #undef res #undef v1 #undef v2 diff --git a/filter/interpret.m4 b/filter/interpret.m4 deleted file mode 100644 index ea91e74e..00000000 --- a/filter/interpret.m4 +++ /dev/null @@ -1,80 +0,0 @@ -m4_divert(-1)m4_dnl -# -# BIRD -- Generator of Filter Instructions -# -# (c) 2018 Maria Matejka -# -# Can be freely distributed and used under the terms of the GNU GPL. -# - -# Common aliases -m4_define(DNL, `m4_dnl') - -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -m4_divert(1) -case INST_NAME(): -#define whati (&(what->i_]]INST_NAME()[[)) -m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]]) -m4_undivert(2) -#undef whati -break; -m4_divert(-1) -]])') - -m4_define(INST, `INST_FLUSH()m4_define([[INST_NAME]], [[$1]])m4_define([[INST_INVAL]], [[$2]])m4_divert(2)') - -m4_define(ARG, `if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)') - -m4_define(RESULT_OK, `vstk.cnt++') -m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') -m4_define(RESULT_VAL, `do { res = $1; RESULT_OK; } while (0)') - -m4_define(LINEX, `do { - estk.item[estk.cnt].pos = 0; - estk.item[estk.cnt].line = $1; - estk.item[estk.cnt].ventry = vstk.cnt; - estk.item[estk.cnt].emask = 0; - estk.cnt++; -} while (0)') - -m4_define(LINE, `do { - if (whati->fl$1) { - estk.item[estk.cnt].pos = 0; - estk.item[estk.cnt].line = whati->fl$1; - estk.item[estk.cnt].ventry = vstk.cnt; - estk.item[estk.cnt].emask = 0; - estk.cnt++; - } -} while (0)') - -m4_define(ARG_ANY, `') - -m4_define(SYMBOL, `const struct symbol *sym = whati->sym') - -m4_define(FRET, `enum filter_return fret = whati->fret') -m4_define(ECS, `enum ec_subtype ecs = whati->ecs') -m4_define(RTC, `struct rtable *table = whati->rtc->table') -m4_define(STATIC_ATTR, `struct f_static_attr sa = whati->sa') -m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = whati->da') -m4_define(TREE, `const struct f_tree *tree = whati->tree') -m4_define(STRING, `') -m4_define(COUNT, `') -m4_define(SAME, `') -m4_define(FID_STRUCT_IN, `m4_divert(-1)') -m4_define(FID_LINE_IN, `m4_divert(-1)') -m4_define(FID_NEW_ARGS, `m4_divert(-1)') -m4_define(FID_NEW_BODY, `m4_divert(-1)') -m4_define(FID_POSTFIXIFY_BODY, `m4_divert(-1)') -m4_define(FID_SAME_BODY, `m4_divert(-1)') -m4_define(FID_DUMP_BODY, `m4_divert(-1)') -m4_define(FID_END, `m4_divert(2)') - -m4_m4wrap(` -INST_FLUSH() -m4_divert(0)DNL -m4_undivert(1) -default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); -') - -m4_changequote([[,]]) - diff --git a/filter/test.conf b/filter/test.conf index dc47eb7d..b9f1b3aa 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -1381,3 +1381,9 @@ protocol static vpn4 { table v4; import filter vpn_filter; }; route 0:1:2 10.1.10.0/24 unreachable; } + +protocol static +{ + ipv6 { import where false; }; + route fd01::/48 unreachable; +} From ad702bae0ce95ee1913327dd13a877e6bf9b320d Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 20 Feb 2019 22:14:28 +0100 Subject: [PATCH 38/88] Enabled link time optimization. --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 850e771f..6b5fc233 100644 --- a/configure.ac +++ b/configure.ac @@ -137,12 +137,14 @@ if test "$bird_cflags_default" = yes ; then BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers], [-Wall -Wextra]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) + BIRD_CHECK_GCC_OPTION([bird_cv_c_option_flto], [-flto]) CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses" BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_pointer_sign], [-Wno-pointer-sign]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) + BIRD_ADD_GCC_OPTION([bird_cv_c_option_flto], [-flto]) fi AC_MSG_CHECKING([CFLAGS]) AC_MSG_RESULT([$CFLAGS]) From 412614c700085ac964b07ff9405403eaf02fa5b4 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 22 Feb 2019 12:41:51 +0100 Subject: [PATCH 39/88] Conf: Switch for faster (and slightly bigger) lexer --- conf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/Makefile b/conf/Makefile index be823d40..3b65ad1e 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -23,7 +23,7 @@ $(o)cf-parse.tab.c: $(o)cf-parse.y $(BISON) $(BISON_DEBUG) $(BISONFLAGS) -dv -pcf_ -b $(@:.tab.c=) $< $(o)cf-lex.c: $(s)cf-lex.l - $(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcf_ -o$@ $< + $(FLEX) $(FLEX_DEBUG) -f -s -B -8 -Pcf_ -o$@ $< $(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h $(o)cf-lex.o: CFLAGS+=-Wno-sign-compare -Wno-unused-function From 99911873a196975f5221aad89ae5eac42e1330e0 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 25 Feb 2019 17:19:47 +0100 Subject: [PATCH 40/88] Conf: Lexer parses quoted strings in a more descriptive way --- conf/cf-lex.l | 137 +++++++++++++++++++++++++++++++++----------------- conf/conf.h | 4 +- 2 files changed, 92 insertions(+), 49 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index f1b402a0..45327cd9 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -65,7 +65,7 @@ struct keyword { #endif -static uint cf_hash(byte *c); +static uint cf_hash(const byte *c); #define KW_KEY(n) n->name #define KW_NEXT(n) n->next @@ -96,6 +96,15 @@ int (*cf_read_hook)(byte *buf, unsigned int max, int fd); struct include_file_stack *ifs; static struct include_file_stack *ifs_head; +#define QUOTED_BUFFER_SIZE 4096 +static BUFFER_(char) quoted_buffer; +static char quoted_buffer_data[QUOTED_BUFFER_SIZE]; +static inline void quoted_buffer_init(void) { + quoted_buffer.used = 0; + quoted_buffer.size = QUOTED_BUFFER_SIZE; + quoted_buffer.data = quoted_buffer_data; +} + #define MAX_INCLUDE_DEPTH 8 #define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd); @@ -106,6 +115,8 @@ static struct include_file_stack *ifs_head; static void cf_include(char *arg, int alen); static int check_eof(void); +static enum yytokentype cf_lex_symbol(const char *data); + %} %option noyywrap @@ -113,24 +124,26 @@ static int check_eof(void); %option nounput %option noreject -%x COMMENT CCOMM CLI +%x COMMENT CCOMM CLI QUOTED APOSTROPHED INCLUDE ALPHA [a-zA-Z_] DIGIT [0-9] XIGIT [0-9a-fA-F] ALNUM [a-zA-Z_0-9] WHITE [ \t] -include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; %% -{include} { - char *start, *end; - +^{WHITE}*include{WHITE}*\" { if (!ifs->depth) cf_error("Include not allowed in CLI"); - start = strchr(yytext, '"'); - start++; + BEGIN(INCLUDE); +} + +[^"\n]+["]{WHITE}*; { + char *start, *end; + + start = yytext; end = strchr(start, '"'); *end = 0; @@ -139,8 +152,16 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; cf_error("Include with empty argument"); cf_include(start, end-start); + + BEGIN(INITIAL); } +["] cf_error("Include with empty argument"); +. cf_error("Unterminated include"); +\n cf_error("Unterminated include"); +<> cf_error("Unterminated include"); + + {DIGIT}+:{DIGIT}+ { uint len1 UNUSED, len2; u64 l; @@ -267,37 +288,23 @@ else: { return ELSECOL; } -({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) { - if(*yytext == '\'') { - yytext[yyleng-1] = 0; - yytext++; - } +['] { + BEGIN(APOSTROPHED); + quoted_buffer_init(); +} - struct keyword *k = HASH_FIND(kw_hash, KW, yytext); - if (k) - { - if (k->value > 0) - return k->value; - else - { - cf_lval.i = -k->value; - return ENUM; - } - } +{ALNUM}|[-]|[.:] BUFFER_PUSH(quoted_buffer) = yytext[0]; +\n cf_error("Unterminated symbol"); +<> cf_error("Unterminated symbol"); +['] { + BEGIN(INITIAL); + BUFFER_PUSH(quoted_buffer) = 0; + return cf_lex_symbol(quoted_buffer_data); +} +. cf_error("Invalid character in apostrophed symbol"); - cf_lval.s = cf_get_symbol(yytext); - switch (cf_lval.s->class) { - case SYM_VOID: return CF_SYM_VOID; - case SYM_PROTO: return CF_SYM_PROTO; - case SYM_TEMPLATE: return CF_SYM_TEMPLATE; - case SYM_FUNCTION: return CF_SYM_FUNCTION; - case SYM_FILTER: return CF_SYM_FILTER; - case SYM_TABLE: return CF_SYM_TABLE; - case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE; - case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE; - case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT; - default: bug("Unknown symbol class %d", cf_lval.s->class); - } +({ALPHA}{ALNUM}*) { + return cf_lex_symbol(yytext); } (.|\n) { @@ -313,14 +320,21 @@ else: { return yytext[0]; } -["][^"\n]*["] { - yytext[yyleng-1] = 0; - cf_lval.t = cfg_strdup(yytext+1); - yytext[yyleng-1] = '"'; +["] { + BEGIN(QUOTED); + quoted_buffer_init(); +} + +\n cf_error("Unterminated string"); +<> cf_error("Unterminated string"); +["] { + BEGIN(INITIAL); + BUFFER_PUSH(quoted_buffer) = 0; + cf_lval.t = cfg_strdup(quoted_buffer_data); return TEXT; } -["][^"\n]*\n cf_error("Unterminated string"); +. BUFFER_PUSH(quoted_buffer) = yytext[0]; <> { if (check_eof()) return END; } @@ -361,7 +375,7 @@ else: { %% static uint -cf_hash(byte *c) +cf_hash(const byte *c) { uint h = 13 << 24; @@ -370,7 +384,6 @@ cf_hash(byte *c) return h; } - /* * IFS stack - it contains structures needed for recursive processing * of include in config files. On the top of the stack is a structure @@ -531,7 +544,7 @@ check_eof(void) } static struct symbol * -cf_new_symbol(byte *c) +cf_new_symbol(const byte *c) { struct symbol *s; @@ -563,7 +576,7 @@ cf_new_symbol(byte *c) * signify no match. */ struct symbol * -cf_find_symbol(struct config *cfg, byte *c) +cf_find_symbol(struct config *cfg, const byte *c) { struct symbol *s; @@ -590,7 +603,7 @@ cf_find_symbol(struct config *cfg, byte *c) * existing symbol is found. */ struct symbol * -cf_get_symbol(byte *c) +cf_get_symbol(const byte *c) { return cf_find_symbol(new_config, c) ?: cf_new_symbol(c); } @@ -636,6 +649,36 @@ cf_default_name(char *template, int *counter) cf_error("Unable to generate default name"); } +static enum yytokentype +cf_lex_symbol(const char *data) +{ + struct keyword *k = HASH_FIND(kw_hash, KW, data); + if (k) + { + if (k->value > 0) + return k->value; + else + { + cf_lval.i = -k->value; + return ENUM; + } + } + + cf_lval.s = cf_get_symbol(data); + switch (cf_lval.s->class) { + case SYM_VOID: return CF_SYM_VOID; + case SYM_PROTO: return CF_SYM_PROTO; + case SYM_TEMPLATE: return CF_SYM_TEMPLATE; + case SYM_FUNCTION: return CF_SYM_FUNCTION; + case SYM_FILTER: return CF_SYM_FILTER; + case SYM_TABLE: return CF_SYM_TABLE; + case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE; + case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE; + case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT; + default: bug("Unknown symbol class %d", cf_lval.s->class); + } +} + static void cf_lex_init_kh(void) { diff --git a/conf/conf.h b/conf/conf.h index 21d4f1e2..acb3413b 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -167,9 +167,9 @@ int cf_lex(void); void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); -struct symbol *cf_find_symbol(struct config *cfg, byte *c); +struct symbol *cf_find_symbol(struct config *cfg, const byte *c); -struct symbol *cf_get_symbol(byte *c); +struct symbol *cf_get_symbol(const byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_localize_symbol(struct symbol *sym); From 2915e711f77d68dff756babd19af8da1677c4549 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 25 Feb 2019 23:28:36 +0100 Subject: [PATCH 41/88] Custom number parser to speed up config parsing The glibc's generic parser is slow due to its versatility. Specialized parsers for base-10 and base-16 are much faster and we don't use other bases. --- conf/cf-lex.l | 14 ++++++------ lib/Makefile | 2 +- lib/ip.c | 2 +- lib/string.h | 4 ++++ lib/strtoul.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 lib/strtoul.c diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 45327cd9..593df9d6 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -168,7 +168,7 @@ WHITE [ \t] char *e; errno = 0; - l = strtoul(yytext, &e, 10); + l = bstrtoul(yytext, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> 32)) cf_error("ASN out of range"); @@ -186,7 +186,7 @@ WHITE [ \t] } errno = 0; - l = strtoul(e+1, &e, 10); + l = bstrtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -213,13 +213,13 @@ WHITE [ \t] } errno = 0; - l = strtoul(yytext+2, &e, 10); + l = bstrtoul(yytext+2, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> len1)) cf_error("ASN out of range"); cf_lval.i64 |= ((u64) l) << len2; errno = 0; - l = strtoul(e+1, &e, 10); + l = bstrtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -241,7 +241,7 @@ WHITE [ \t] cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16; errno = 0; - l = strtoul(e, &e, 10); + l = bstrtoul(e, &e, 10); if (e && *e || (errno == ERANGE) || (l >> 16)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -265,7 +265,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = strtoul(yytext+2, &e, 16); + l = bstrtoul(yytext+2, &e, 16); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; @@ -276,7 +276,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = strtoul(yytext, &e, 10); + l = bstrtoul(yytext, &e, 10); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; diff --git a/lib/Makefile b/lib/Makefile index 01f3114d..18816bb3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c timer.c xmalloc.c +src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c obj := $(src-o-files) $(all-daemon) diff --git a/lib/ip.c b/lib/ip.c index 9497248c..0f5a5348 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -245,7 +245,7 @@ ip4_pton(const char *a, ip4_addr *o) char *d, *c = strchr(a, '.'); if (!c != !i) return 0; - l = strtoul(a, &d, 10); + l = bstrtoul(a, &d, 10); if (((d != c) && *d) || (l > 255)) return 0; ia = (ia << 8) | l; diff --git a/lib/string.h b/lib/string.h index 0d34f9c5..5f7c4666 100644 --- a/lib/string.h +++ b/lib/string.h @@ -24,6 +24,10 @@ int buffer_vprint(buffer *buf, const char *fmt, va_list args); int buffer_print(buffer *buf, const char *fmt, ...); void buffer_puts(buffer *buf, const char *str); +#define bstrtoul(str, end, base) bstrtoul##base(str, end) +u64 bstrtoul10(const char *str, char **end); +u64 bstrtoul16(const char *str, char **end); + int patmatch(const byte *pat, const byte *str); static inline char *xbasename(const char *str) diff --git a/lib/strtoul.c b/lib/strtoul.c new file mode 100644 index 00000000..44a1bb1d --- /dev/null +++ b/lib/strtoul.c @@ -0,0 +1,61 @@ +/* + * BIRD Library -- Parse numbers + * + * (c) 2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "lib/string.h" + +#include + +#define ULI_MAX_DIV10 (UINT64_MAX / 10) +#define ULI_MAX_MOD10 (UINT64_MAX % 10) + +u64 +bstrtoul10(const char *str, char **end) +{ + u64 out = 0; + for (*end = (char *) str; (**end >= '0') && (**end <= '9'); (*end)++) { + u64 digit = **end - '0'; + if ((out > ULI_MAX_DIV10) || + (out == ULI_MAX_DIV10) && (digit > ULI_MAX_MOD10)) { + errno = ERANGE; + return UINT64_MAX; + } + + out *= 10; + out += (**end) - '0'; + } + return out; +} + +u64 +bstrtoul16(const char *str, char **end) +{ + u64 out = 0; + for (int i=0; i<=(64/4); i++) { + switch (str[i]) { + case '0' ... '9': + out *= 16; + out += str[i] - '0'; + break; + case 'a' ... 'f': + out *= 16; + out += str[i] + 10 - 'a'; + break; + case 'A' ... 'F': + out *= 16; + out += str[i] + 10 - 'A'; + break; + default: + *end = (char *) &(str[i]); + return out; + } + } + + errno = ERANGE; + return UINT64_MAX; +} From 0d12aa48363802e751d3b9a4afd6eb090592d7a3 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 26 Feb 2019 16:11:40 +0100 Subject: [PATCH 42/88] Build: No link time optimization when debug is enabled --- configure.ac | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6b5fc233..7013a34e 100644 --- a/configure.ac +++ b/configure.ac @@ -137,14 +137,18 @@ if test "$bird_cflags_default" = yes ; then BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers], [-Wall -Wextra]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) - BIRD_CHECK_GCC_OPTION([bird_cv_c_option_flto], [-flto]) + if test "$enable_debug" = no; then + BIRD_CHECK_GCC_OPTION([bird_cv_c_option_flto], [-flto]) + fi CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses" BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_pointer_sign], [-Wno-pointer-sign]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) - BIRD_ADD_GCC_OPTION([bird_cv_c_option_flto], [-flto]) + if test "$enable_debug" = no; then + BIRD_ADD_GCC_OPTION([bird_cv_c_option_flto], [-flto]) + fi fi AC_MSG_CHECKING([CFLAGS]) AC_MSG_RESULT([$CFLAGS]) From f249d0b84c840242a084966999a1d228c603b431 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 26 Feb 2019 16:44:24 +0100 Subject: [PATCH 43/88] Filters: comparison of functions and filters caching --- conf/cf-lex.l | 4 ++- conf/conf.c | 3 +++ conf/conf.h | 4 ++- filter/config.Y | 2 +- filter/f-inst.h | 4 +-- filter/f-util.c | 9 +++---- filter/filter.c | 46 +++++++++++++++++++++++++++++++++-- filter/filter.h | 4 ++- filter/test-reconf-begin.conf | 23 ++++++++++++++++++ filter/test-reconf-end.conf | 23 ++++++++++++++++++ 10 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 filter/test-reconf-begin.conf create mode 100644 filter/test-reconf-end.conf diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 593df9d6..4f69993e 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -561,6 +561,8 @@ cf_new_symbol(const byte *c) HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s); + add_tail(&(new_config->symbols), &(s->n)); + return s; } @@ -576,7 +578,7 @@ cf_new_symbol(const byte *c) * signify no match. */ struct symbol * -cf_find_symbol(struct config *cfg, const byte *c) +cf_find_symbol(const struct config *cfg, const byte *c) { struct symbol *s; diff --git a/conf/conf.c b/conf/conf.c index 439aa41d..b0980d7e 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -98,6 +98,7 @@ config_alloc(const char *name) memcpy(ndup, name, nlen); init_list(&c->tests); + init_list(&c->symbols); c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */ c->pool = p; c->mem = l; @@ -258,6 +259,8 @@ config_do_commit(struct config *c, int type) if (old_config) old_config->obstacle_count++; + DBG("filter_commit\n"); + filter_commit(c, old_config); DBG("sysdep_commit\n"); int force_restart = sysdep_commit(c, old_config); DBG("global_commit\n"); diff --git a/conf/conf.h b/conf/conf.h index acb3413b..f14c0e21 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -24,6 +24,7 @@ struct config { list tables; /* Configured routing tables (struct rtable_config) */ list logfiles; /* Configured log files (sysdep) */ list tests; /* Configured unit tests (f_bt_test_suite) */ + list symbols; /* Configured symbols in config order */ int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */ char *syslog_name; /* Name used for syslog (NULL -> no syslog) */ @@ -103,6 +104,7 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size); extern int (*cf_read_hook)(byte *buf, uint max, int fd); struct symbol { + node n; /* In list of symbols in config */ struct symbol *next; struct sym_scope *scope; int class; /* SYM_* */ @@ -167,7 +169,7 @@ int cf_lex(void); void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); -struct symbol *cf_find_symbol(struct config *cfg, const byte *c); +struct symbol *cf_find_symbol(const struct config *cfg, const byte *c); struct symbol *cf_get_symbol(const byte *c); struct symbol *cf_default_name(char *template, int *counter); diff --git a/filter/config.Y b/filter/config.Y index 5ec226f0..a7618987 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -470,7 +470,7 @@ filter_def: FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } filter_body { struct filter *f = cfg_alloc(sizeof(struct filter)); - *f = (struct filter) { .name = $2->name, .root = $4 }; + *f = (struct filter) { .sym = $2, .root = $4 }; $2->filter = f; cf_pop_scope(); diff --git a/filter/f-inst.h b/filter/f-inst.h index 5b397a5d..4b42c57c 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -31,12 +31,10 @@ const char *f_instruction_name(enum f_instruction_code fi); struct f_inst *f_clear_local_vars(struct f_inst *decls); /* Filter structures for execution */ -struct f_line; - /* Line of instructions to be unconditionally executed one after another */ struct f_line { uint len; /* Line length */ - u16 args; /* Function: Args required */ + u8 args; /* Function: Args required */ struct f_line_item items[0]; /* The items themselves */ }; diff --git a/filter/f-util.c b/filter/f-util.c index 85f5d1c4..35944b2c 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -24,10 +24,10 @@ filter_name(const struct filter *filter) return "ACCEPT"; else if (filter == FILTER_REJECT) return "REJECT"; - else if (!filter->name) + else if (!filter->sym) return "(unnamed)"; else - return filter->name; + return filter->sym->name; } void f_inst_next(struct f_inst *first, const struct f_inst *append) @@ -54,7 +54,7 @@ struct filter *f_new_where(const struct f_inst *where) struct f_inst i = { .fi_code = FI_CONDITION, .lineno = ifs->lino, - .size = 3, + .size = 3 + where->size, .i_FI_CONDITION = { .f1 = where, .f2 = &acc, @@ -62,8 +62,7 @@ struct filter *f_new_where(const struct f_inst *where) }, }; - struct filter *f = cfg_alloc(sizeof(struct filter)); - f->name = NULL; + struct filter *f = cfg_allocz(sizeof(struct filter)); f->root = f_postfixify(&i); return f; } diff --git a/filter/filter.c b/filter/filter.c index ee5d5426..3be7343c 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -293,7 +293,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i if (fret < F_ACCEPT) { if (!(fs.flags & FF_SILENT)) - log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); + log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter_name(filter)); return F_ERROR; } DBG( "done (%u)\n", res.val.i ); @@ -378,5 +378,47 @@ filter_same(const struct filter *new, const struct filter *old) if (old == FILTER_ACCEPT || old == FILTER_REJECT || new == FILTER_ACCEPT || new == FILTER_REJECT) return 0; - return f_same(new->root, old->root); + + if ((!old->sym) && (!new->sym)) + return f_same(new->root, old->root); + + if ((!old->sym) || (!new->sym)) + return 0; + + if (strcmp(old->sym->name, new->sym->name)) + return 0; + + return new->sym->flags & SYM_FLAG_SAME; +} + +/** + * filter_commit - do filter comparisons on all the named functions and filters + */ +void +filter_commit(const struct config *new, const struct config *old) +{ + if (!old) + return; + + struct symbol *sym, *osym; + WALK_LIST(sym, new->symbols) + switch (sym->class) { + case SYM_FUNCTION: + if ((osym = cf_find_symbol(old, sym->name)) && + (osym->class == SYM_FUNCTION) && + f_same(sym->function, osym->function)) + sym->flags |= SYM_FLAG_SAME; + else + sym->flags &= ~SYM_FLAG_SAME; + break; + + case SYM_FILTER: + if ((osym = cf_find_symbol(old, sym->name)) && + (osym->class == SYM_FILTER) && + f_same(sym->filter->root, osym->filter->root)) + sym->flags |= SYM_FLAG_SAME; + else + sym->flags &= ~SYM_FLAG_SAME; + break; + } } diff --git a/filter/filter.h b/filter/filter.h index 26faeaa3..d919cc74 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -47,7 +47,7 @@ struct f_val; /* The filter encapsulating structure to be pointed-to from outside */ struct f_line; struct filter { - char *name; + struct symbol *sym; const struct f_line *root; }; @@ -62,6 +62,8 @@ const char *filter_name(const struct filter *filter); int filter_same(const struct filter *new, const struct filter *old); int f_same(const struct f_line *f1, const struct f_line *f2); +void filter_commit(const struct config *new, const struct config *old); + #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) #define FILTER_UNDEF ((void *) 2) /* Used in BGP */ diff --git a/filter/test-reconf-begin.conf b/filter/test-reconf-begin.conf new file mode 100644 index 00000000..aeed007f --- /dev/null +++ b/filter/test-reconf-begin.conf @@ -0,0 +1,23 @@ +router id 1.1.1.1; +protocol device {} + +function a() { + return true; +} + +function b() { + return a(); +} + +function c() { + return b(); +} + +filter d { + if c() then accept; else reject; +} + +protocol static { + ipv4 { import filter d; }; + route 10.0.0.0/24 unreachable; +} diff --git a/filter/test-reconf-end.conf b/filter/test-reconf-end.conf new file mode 100644 index 00000000..19164825 --- /dev/null +++ b/filter/test-reconf-end.conf @@ -0,0 +1,23 @@ +router id 1.1.1.1; +protocol device {} + +function a() { + return false; +} + +function b() { + return a(); +} + +function c() { + return b(); +} + +filter d { + if c() then accept; else reject; +} + +protocol static { + ipv4 { import filter d; }; + route 10.0.0.0/24 unreachable; +} From a68442e0563f5b756f9a7323cea44a25ce048738 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 27 Feb 2019 14:40:05 +0100 Subject: [PATCH 44/88] Fixed link time optimizer check for FreeBSD --- aclocal.m4 | 24 ++++++++++++++++++++++++ configure.ac | 14 ++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/aclocal.m4 b/aclocal.m4 index c401d447..0044adf9 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -131,6 +131,30 @@ AC_DEFUN([BIRD_CHECK_ANDROID_LOG], ) ]) +AC_DEFUN([BIRD_CHECK_LTO], +[ + bird_tmp_cflags="$CFLAGS" + bird_tmp_ldflags="$CFLAGS" + CFLAGS="-flto" + LDFLAGS="-flto" + + AC_CACHE_CHECK( + [whether link time optimizer is available], + [bird_cv_c_lto], + [ + AC_LINK_IFELSE( + [AC_LANG_PROGRAM()], + [bird_cv_c_lto=yes], + [bird_cv_c_lto=no] + ) + ] + ) + + CFLAGS="$bird_tmp_cflags" + LDFLAGS="$bird_tmp_ldflags" +]) + + AC_DEFUN([BIRD_CHECK_GCC_OPTION], [ bird_tmp_cflags="$CFLAGS" diff --git a/configure.ac b/configure.ac index 7013a34e..58fdc7fe 100644 --- a/configure.ac +++ b/configure.ac @@ -137,22 +137,24 @@ if test "$bird_cflags_default" = yes ; then BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers], [-Wall -Wextra]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) - if test "$enable_debug" = no; then - BIRD_CHECK_GCC_OPTION([bird_cv_c_option_flto], [-flto]) - fi CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses" BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_pointer_sign], [-Wno-pointer-sign]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing]) BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow]) - if test "$enable_debug" = no; then - BIRD_ADD_GCC_OPTION([bird_cv_c_option_flto], [-flto]) - fi fi AC_MSG_CHECKING([CFLAGS]) AC_MSG_RESULT([$CFLAGS]) +if test "$enable_debug" = no; then + BIRD_CHECK_LTO +fi + +if test "$bird_cv_c_lto" = yes; then + CFLAGS="$CFLAGS -flto" + LDFLAGS="$LDFLAGS -flto" +fi AC_PROG_CPP AC_PROG_INSTALL From e1ac6f1e301416037725b631fd6529a805e65d51 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 6 Mar 2019 15:01:10 +0100 Subject: [PATCH 45/88] Faster filters: documentation on what is happening there --- filter/f-inst.c | 37 +++++++++++++++++++++++++++++++++++++ filter/f-inst.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/filter/f-inst.c b/filter/f-inst.c index 8505534a..6f031782 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -7,6 +7,43 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * + * Filter instructions. You shall define your instruction only here + * and nowhere else. + * + * Beware. This file is interpreted by M4 macros. These macros + * may be more stupid than you could imagine. If something strange + * happens after changing this file, compare the results before and + * after your change (see the Makefile to find out where the results are) + * and see what really happened. + * + * This file is not directly a C source code -> it is a generator input + * for several C sources; every instruction block gets expanded into many + * different places. + * + * What is the syntax here? + * m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args + * m4_dnl ARG(num, type); argument, its id (in data fields) and type + * m4_dnl ARG_ANY(num); argument with no type check + * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line + * m4_dnl ECS; extended community subtype + * m4_dnl COUNT(unused); simply a uint + * m4_dnl SYMBOL(unused); symbol handed from config + * m4_dnl FRET(unused); filter return value + * m4_dnl STATIC_ATTR; static attribute definition + * m4_dnl DYNAMIC_ATTR; dynamic attribute definition + * m4_dnl RTC; route table config + * m4_dnl TREE; a tree + * m4_dnl ACCESS_RTE; this instruction needs route + * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes + * m4_dnl RESULT(type, union-field, value); putting this on value stack + * m4_dnl RESULT_OK; legalize what already is on the value stack + * m4_dnl } + * + * Other code is just copied into the interpreter part. + * + * If you want to write something really special, see FI_CALL + * or FI_CONSTANT or whatever else to see how to use the FID_* + * macros. */ /* Binary operators */ diff --git a/filter/f-inst.h b/filter/f-inst.h index 4b42c57c..1e2d63a2 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -5,6 +5,41 @@ * (c) 2018--2019 Maria Matejka * * Can be freely distributed and used under the terms of the GNU GPL. + * + * Filter interpreter data structures and internal API. + * The filter code goes through several phases: + * + * 1 Parsing + * Flex- and Bison-generated parser decodes the human-readable data into + * a struct f_inst tree. This is an infix tree that was interpreted by + * depth-first search execution in previous versions of the interpreter. + * All instructions have their constructor: f_new_inst(FI_code, ...) + * translates into f_new_inst_FI_code(...) and the types are checked in + * compile time. + * + * 2 Postfixify before interpreting + * The infix tree is always interpreted in the same order. Therefore we + * sort the instructions one after another into struct f_line. Results + * and arguments of these instructions are implicitly put on a value + * stack; e.g. the + operation just takes two arguments from the value + * stack and puts the result on there. + * + * 3 Interpret + * The given line is put on a custom execution stack. If needed (FI_CALL, + * FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top + * of the stack; when that line finishes, the execution continues on the + * older lines on the stack where it stopped before. + * + * 4 Same + * On config reload, the filters have to be compared whether channel + * reload is needed or not. The comparison is done by comparing the + * struct f_line's recursively. + * + * The main purpose of this rework was to improve filter performance + * by making the interpreter non-recursive. + * + * The other outcome is concentration of instruction definitions to + * one place -- filter/f-inst.c */ #ifndef _BIRD_F_INST_H_ From d638c1794a48dec79fa0a6c118296356754a134d Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 6 Mar 2019 21:45:28 +0100 Subject: [PATCH 46/88] Gitlab CI: Drop CentOS 6 test build as unsupported. If someone wants to maintain BIRD for CentOS 6, feel free to send patches. --- .gitlab-ci.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ff11dda0..4efe0fcf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,11 +79,6 @@ docker_fedora-26-amd64: IMG_NAME: "fedora-26-amd64" <<: *docker_build -docker_centos-6-amd64: - variables: - IMG_NAME: "centos-6-amd64" - <<: *docker_build - docker_centos-7-amd64: variables: IMG_NAME: "centos-7-amd64" @@ -174,13 +169,6 @@ docker_ubuntu-16_04-amd64: - linux - amd64 -.centos-6-amd64: ¢os-6-amd64_env - image: registry.labs.nic.cz/labs/bird:centos-6-amd64 - tags: - - docker - - linux - - amd64 - .centos-7-amd64: ¢os-7-amd64_env image: registry.labs.nic.cz/labs/bird:centos-7-amd64 tags: @@ -264,10 +252,6 @@ build-fedora-26-amd64: <<: *fedora-26-amd64_env <<: *build_job -build-centos-6-amd64: - <<: *centos-6-amd64_env - <<: *build_job - build-centos-7-amd64: <<: *centos-7-amd64_env <<: *build_job From 2f02c25e36f3946019c24dafe9b894a9e195350d Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 7 Mar 2019 18:02:05 +0100 Subject: [PATCH 47/88] Perf: fixed stupid allocation bug --- proto/perf/perf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proto/perf/perf.c b/proto/perf/perf.c index 8412254a..bfc0f09e 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -90,6 +90,8 @@ struct perf_random_routes { struct rta a; }; +static const uint perf_random_routes_size = sizeof(net_addr) + sizeof(rte *) + RTA_MAX_SIZE; + static inline s64 timediff(struct timespec *begin, struct timespec *end) { return (end->tv_sec - begin->tv_sec) * (s64) 1000000000 + end->tv_nsec - begin->tv_nsec; } @@ -124,7 +126,7 @@ perf_loop(void *data) struct perf_proto *p = data; const uint N = 1U << p->exp; - const uint offset = sizeof(net_addr) + RTA_MAX_SIZE; + const uint offset = perf_random_routes_size; if (!p->run) { ASSERT(p->data == NULL); From 2ab680c6972306db71d9a8d4ee4fabf265981d30 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 20 Mar 2019 16:50:58 +0100 Subject: [PATCH 48/88] Fixed an undefined symbol bug in CLI introduced by filter refactoring --- nest/cli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/nest/cli.c b/nest/cli.c index c421cc7e..24962f10 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -262,6 +262,7 @@ cli_command(struct cli *c) bzero(&f, sizeof(f)); f.mem = c->parser_pool; f.pool = rp_new(c->pool, "Config"); + init_list(&f.symbols); cf_read_hook = cli_cmd_read_hook; cli_rh_pos = c->rx_buf; cli_rh_len = strlen(c->rx_buf); From 7078aa63ae498b55c729df4a075eb28019917e81 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 22 Mar 2019 21:40:35 +0100 Subject: [PATCH 49/88] Fixed one warning and one undefined value. --- nest/rt-table.c | 2 +- sysdep/unix/io.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index 12966eca..53f5d979 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1576,7 +1576,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) } else if (filter) { - rta *old_attrs; + rta *old_attrs = NULL; rte_make_tmp_attrs(&new, rte_update_pool, &old_attrs); int fr = f_run(filter, &new, rte_update_pool, 0); diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index d1d86e3b..5b0e49c1 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -132,7 +132,7 @@ times_init(struct timeloop *loop) if (rv < 0) die("Monotonic clock is missing"); - if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40))) + if ((ts.tv_sec < 0) || (((u64) ts.tv_sec) > ((u64) 1 << 40))) log(L_WARN "Monotonic clock is crazy"); loop->last_time = ts.tv_sec S + ts.tv_nsec NS; From fe503c7c0632b385222c92b85d04526fdf36a1a3 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sat, 23 Mar 2019 13:32:14 +0100 Subject: [PATCH 50/88] Filter: fixed error-checking bug in !~ operator --- filter/f-inst.c | 2 +- filter/test.conf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 3fea16c4..d6c292b6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -233,7 +233,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_in_range(&v1, &v2); - if (res.val.i == F_CMP_ERROR) + if (i == F_CMP_ERROR) runtime( "!~ applied on unknown type pair" ); RESULT(T_BOOL, i, !i); } diff --git a/filter/test.conf b/filter/test.conf index b9f1b3aa..ba25a34b 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -136,6 +136,7 @@ int set is; bt_assert(2 ~ [ 1, 2, 3 ]); bt_assert(5 ~ [ 4 .. 7 ]); bt_assert(1 !~ [ 2, 3, 4 ]); + bt_assert(999 !~ [ 666, 333 ]); is = [ 2, 3, 4, 7..11 ]; bt_assert(10 ~ is); From 9eef9c648cee7179e069ea1f978d4e86cef580d3 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 17 May 2019 22:18:49 +0200 Subject: [PATCH 51/88] Lexer now returns known sym / unknown sym / keyword --- conf/cf-lex.l | 24 ++++++++---------- conf/confbase.Y | 62 ++++++++++++++++++++++++++------------------- filter/config.Y | 51 ++++++++++++++++++++++++++----------- nest/config.Y | 43 +++++++++++++++++-------------- proto/ospf/config.Y | 2 +- 5 files changed, 108 insertions(+), 74 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 4f69993e..83e4e77c 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -654,6 +654,14 @@ cf_default_name(char *template, int *counter) static enum yytokentype cf_lex_symbol(const char *data) { + /* Have we defined such a symbol? */ + struct symbol *sym = cf_get_symbol(data); + cf_lval.s = sym; + + if (sym->class != SYM_VOID) + return CF_SYM_KNOWN; + + /* Is it a keyword? */ struct keyword *k = HASH_FIND(kw_hash, KW, data); if (k) { @@ -666,19 +674,9 @@ cf_lex_symbol(const char *data) } } - cf_lval.s = cf_get_symbol(data); - switch (cf_lval.s->class) { - case SYM_VOID: return CF_SYM_VOID; - case SYM_PROTO: return CF_SYM_PROTO; - case SYM_TEMPLATE: return CF_SYM_TEMPLATE; - case SYM_FUNCTION: return CF_SYM_FUNCTION; - case SYM_FILTER: return CF_SYM_FILTER; - case SYM_TABLE: return CF_SYM_TABLE; - case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE; - case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE; - case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT; - default: bug("Unknown symbol class %d", cf_lval.s->class); - } + /* OK, undefined symbol */ + cf_lval.s = sym; + return CF_SYM_UNDEFINED; } static void diff --git a/conf/confbase.Y b/conf/confbase.Y index dcc92365..e104e54f 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -33,6 +33,21 @@ check_u16(uint val) cf_error("Value %u out of range (0-65535)", val); } +#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0) +static inline void cf_assert_symbol(const struct symbol *sym, uint class) { + switch (class) { + case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break; + case SYM_TEMPLATE: cf_assert(sym->class == SYM_TEMPLATE, "Protocol template name required"); break; + case SYM_FUNCTION: cf_assert(sym->class == SYM_FUNCTION, "Function name required"); break; + case SYM_FILTER: cf_assert(sym->class == SYM_FILTER, "Filter name required"); break; + case SYM_TABLE: cf_assert(sym->class == SYM_TABLE, "Table name required"); break; + case SYM_ATTRIBUTE: cf_assert(sym->class == SYM_ATTRIBUTE, "Custom attribute name required"); break; + case SYM_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break; + case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break; + default: bug("This shall not happen"); + } +} + CF_DECLS %union { @@ -82,7 +97,7 @@ CF_DECLS %token IP4 %token IP6 %token VPN_RD -%token CF_SYM_VOID CF_SYM_PROTO CF_SYM_TEMPLATE CF_SYM_FUNCTION CF_SYM_FILTER CF_SYM_TABLE CF_SYM_ATTRIBUTE CF_SYM_VARIABLE CF_SYM_CONSTANT +%token CF_SYM_KNOWN CF_SYM_UNDEFINED %token TEXT %type ipa_scope @@ -92,6 +107,7 @@ CF_DECLS %type net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ %type label_stack_start label_stack +%type CF_SYM_VOID %type text opttext %type symbol @@ -104,6 +120,8 @@ CF_DECLS %left '!' %nonassoc '.' +%start config + CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM) CF_GRAMMAR @@ -137,8 +155,8 @@ definition: expr: NUM | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } - | CF_SYM_CONSTANT { - if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected"); + | CF_SYM_KNOWN { + if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected"); $$ = SYM_VAL($1).i; } ; @@ -148,17 +166,9 @@ expr_us: | expr US { $$ = $1 US_; } ; -symbol: - CF_SYM_VOID - | CF_SYM_PROTO - | CF_SYM_TEMPLATE - | CF_SYM_FUNCTION - | CF_SYM_FILTER - | CF_SYM_TABLE - | CF_SYM_ATTRIBUTE - | CF_SYM_VARIABLE - | CF_SYM_CONSTANT - ; +CF_SYM_VOID: CF_SYM_UNDEFINED ; + +symbol: CF_SYM_VOID | CF_SYM_KNOWN ; /* Switches */ @@ -177,8 +187,8 @@ bool: ipa: IP4 { $$ = ipa_from_ip4($1); } | IP6 { $$ = ipa_from_ip6($1); } - | CF_SYM_CONSTANT { - if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected"); + | CF_SYM_KNOWN { + if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected"); $$ = SYM_VAL($1).ip; } ; @@ -292,27 +302,27 @@ net_: net_ip6: net_ip6_ - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6)) - cf_error("IPv6 network expected"); + cf_error("IPv6 network constant expected"); $$ = * SYM_VAL($1).net; } ; net_ip: net_ip_ - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net)) - cf_error("IP network expected"); + cf_error("IP network constant expected"); $$ = * SYM_VAL($1).net; } ; net_any: net_ - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if ($1->class != (SYM_CONSTANT | T_NET)) - cf_error("Network expected"); + cf_error("Network constant expected"); $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */ } ; @@ -322,13 +332,13 @@ net_or_ipa: | net_ip6_ | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); } | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); } - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if ($1->class == (SYM_CONSTANT | T_IP)) net_fill_ip_host(&($$), SYM_VAL($1).ip); else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net)) $$ = * SYM_VAL($1).net; else - cf_error("IP address or network expected"); + cf_error("IP address or network constant expected"); } ; @@ -359,8 +369,8 @@ time: text: TEXT - | CF_SYM_CONSTANT { - if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected"); + | CF_SYM_KNOWN { + if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected"); $$ = SYM_VAL($1).s; } ; diff --git a/filter/config.Y b/filter/config.Y index a7618987..3eccc3ed 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -489,7 +489,8 @@ custom_attr: ATTRIBUTE type CF_SYM_VOID ';' { conf: bt_test_suite ; bt_test_suite: - BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' { + BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' { + cf_assert_symbol($3, SYM_FUNCTION); struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); t->fn = $3->function; t->fn_name = $3->name; @@ -501,7 +502,9 @@ bt_test_suite: conf: bt_test_same ; bt_test_same: - BT_TEST_SAME '(' CF_SYM_FUNCTION ',' CF_SYM_FUNCTION ',' NUM ')' { + BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' { + cf_assert_symbol($3, SYM_FUNCTION); + cf_assert_symbol($5, SYM_FUNCTION); struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); t->fn = $3->function; t->cmp = $5->function; @@ -589,7 +592,8 @@ filter_body: ; filter: - CF_SYM_FILTER { + CF_SYM_KNOWN { + cf_assert_symbol($1, SYM_FILTER); $$ = $1->filter; } | filter_body { @@ -699,7 +703,8 @@ set_atom: if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { + cf_assert_symbol($1, SYM_CONSTANT); if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); $$ = *$1->val; } @@ -858,15 +863,25 @@ constructor: function_call: - CF_SYM_FUNCTION '(' var_list ')' { + CF_SYM_KNOWN '(' var_list ')' { $$ = f_new_inst(FI_CALL, $1, $3); } ; -symbol_value: - CF_SYM_CONSTANT { $$ = f_new_inst(FI_VARIABLE, $1); } - | CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); } - | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *$1->attribute); } +symbol_value: CF_SYM_KNOWN + { + switch ($1->class) { + case SYM_CONSTANT_RANGE: + case SYM_VARIABLE_RANGE: + $$ = f_new_inst(FI_VARIABLE, $1); + break; + case SYM_ATTRIBUTE: + $$ = f_new_inst(FI_EA_GET, *$1->attribute); + break; + default: + cf_error("Can't get value of symbol %s", $1->name); + } + } ; static_attr: @@ -993,11 +1008,17 @@ cmd: | IF term THEN block ELSE block { $$ = f_new_inst(FI_CONDITION, $2, $4, $6); } - | CF_SYM_ATTRIBUTE '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); - } - | CF_SYM_VARIABLE '=' term ';' { - $$ = f_new_inst(FI_SET, $3, $1); + | CF_SYM_KNOWN '=' term ';' { + switch ($1->class) { + case SYM_VARIABLE_RANGE: + $$ = f_new_inst(FI_SET, $3, $1); + break; + case SYM_ATTRIBUTE: + $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); + break; + default: + cf_error("Can't assign to symbol %s", $1->name); + } } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); @@ -1038,7 +1059,7 @@ get_cf_position: }; lvalue: - CF_SYM_VARIABLE { $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } + CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; } | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; diff --git a/nest/config.Y b/nest/config.Y index c2622ed2..fe642489 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -88,7 +88,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID) %type idval %type imexport %type rtable -%type optproto sym_proto_or_template +%type optproto %type r_args %type sym_args %type proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm @@ -114,7 +114,7 @@ idval: NUM { $$ = $1; } | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } | IP4 { $$ = ip4_to_u32($1); } - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) $$ = SYM_VAL($1).i; else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip)) @@ -173,8 +173,6 @@ proto_start: | TEMPLATE { $$ = SYM_TEMPLATE; } ; -sym_proto_or_template: CF_SYM_PROTO | CF_SYM_TEMPLATE ; - proto_name: /* EMPTY */ { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); @@ -186,20 +184,22 @@ proto_name: cf_define_symbol($1, this_proto->class, proto, this_proto); this_proto->name = $1->name; } - | FROM sym_proto_or_template { + | FROM CF_SYM_KNOWN { + if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); + struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); s->class = this_proto->class; s->proto = this_proto; this_proto->name = s->name; - if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); proto_copy_config(this_proto, $2->proto); } - | CF_SYM_VOID FROM sym_proto_or_template { + | CF_SYM_VOID FROM CF_SYM_KNOWN { + if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); + cf_define_symbol($1, this_proto->class, proto, this_proto); this_proto->name = $1->name; - if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); proto_copy_config(this_proto, $3->proto); } ; @@ -256,7 +256,7 @@ channel_end: proto_channel: channel_start channel_opt_list channel_end; -rtable: CF_SYM_TABLE { $$ = $1->table; } ; +rtable: CF_SYM_KNOWN { cf_assert_symbol($1, SYM_TABLE); $$ = $1->table; } ; imexport: FILTER filter { $$ = $2; } @@ -510,7 +510,7 @@ CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show rou { proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; optproto: - CF_SYM_PROTO + CF_SYM_KNOWN { cf_assert_symbol($1, SYM_PROTO); $$ = $1; } | /* empty */ { $$ = NULL; } ; @@ -542,7 +542,8 @@ r_args: $$->show_for = 1; $$->addr = $3; } - | r_args TABLE CF_SYM_TABLE { + | r_args TABLE CF_SYM_KNOWN { + cf_assert_symbol($3, SYM_TABLE); $$ = $1; rt_show_add_table($$, $3->table->table); $$->tables_defined_by = RSD_TDB_DIRECT; @@ -554,7 +555,8 @@ r_args: rt_show_add_table($$, t->table); $$->tables_defined_by = RSD_TDB_ALL; } - | r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel { + | r_args IMPORT TABLE CF_SYM_KNOWN '.' r_args_channel { + cf_assert_symbol($4, SYM_PROTO); $$ = $1; struct proto_config *cf = $4->proto; if (!cf->proto) cf_error("%s is not a protocol", $4->name); @@ -586,7 +588,8 @@ r_args: $$ = $1; $$->filtered = 1; } - | r_args export_mode CF_SYM_PROTO { + | r_args export_mode CF_SYM_KNOWN { + cf_assert_symbol($3, SYM_PROTO); struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); @@ -595,7 +598,8 @@ r_args: $$->export_protocol = c->proto; $$->tables_defined_by = RSD_TDB_INDIRECT; } - | r_args export_mode CF_SYM_PROTO '.' r_args_channel { + | r_args export_mode CF_SYM_KNOWN '.' r_args_channel { + cf_assert_symbol($3, SYM_PROTO); struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->export_mode) cf_error("Export specified twice"); @@ -605,7 +609,8 @@ r_args: if (!$$->export_channel) cf_error("Export channel not found"); $$->tables_defined_by = RSD_TDB_INDIRECT; } - | r_args PROTOCOL CF_SYM_PROTO { + | r_args PROTOCOL CF_SYM_KNOWN { + cf_assert_symbol($3, SYM_PROTO); struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; if ($$->show_protocol) cf_error("Protocol specified twice"); @@ -643,7 +648,7 @@ r_args_for: $$ = cfg_alloc(sizeof(net_addr_ip6_sadr)); net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH); } - | CF_SYM_CONSTANT { + | CF_SYM_KNOWN { if ($1->class == (SYM_CONSTANT | T_IP)) { $$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6)); @@ -652,7 +657,7 @@ r_args_for: else if (($1->class == (SYM_CONSTANT | T_NET)) && net_type_match(SYM_VAL($1).net, NB_IP | NB_VPN)) $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */ else - cf_error("IP address or network expected"); + cf_error("IP address or network constant expected"); } ; @@ -775,13 +780,13 @@ CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]]) { this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; proto_patt: - CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; } + CF_SYM_KNOWN { cf_assert_symbol($1, SYM_PROTO); $$.ptr = $1; $$.patt = 0; } | ALL { $$.ptr = NULL; $$.patt = 1; } | TEXT { $$.ptr = $1; $$.patt = 1; } ; proto_patt2: - CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; } + CF_SYM_KNOWN { cf_assert_symbol($1, SYM_PROTO); $$.ptr = $1; $$.patt = 0; } | { $$.ptr = NULL; $$.patt = 1; } | TEXT { $$.ptr = $1; $$.patt = 1; } ; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 38b09deb..66cf60c1 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -544,7 +544,7 @@ lsadb_args: | lsadb_args LSID idval { $$ = $1; $$->lsid = $3; } | lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; } | lsadb_args ROUTER idval { $$ = $1; $$->router = $3; } - | lsadb_args CF_SYM_PROTO { $$ = $1; $$->proto = (struct ospf_proto *) proto_get_named($2, &proto_ospf); } + | lsadb_args CF_SYM_KNOWN { cf_assert_symbol($2, SYM_PROTO); $$ = $1; $$->proto = (struct ospf_proto *) proto_get_named($2, &proto_ospf); } ; CF_CODE From 20c6ea70ccb69f3c1d9ca46cc7941eb686f283c6 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Mon, 20 May 2019 17:53:10 +0000 Subject: [PATCH 52/88] Filter: Making the filter state thread local. While having the filter code still reentrant if we really need, the compiler can now do constant propagation and address the thread local storage directly to save some computation time. --- filter/filter.c | 94 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 3be7343c..50d9414b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -51,14 +51,19 @@ #include "filter/data.h" /* Internal filter state, to be allocated on stack when executing filters */ -struct filter_state { +_Thread_local struct filter_state { + /* The route we are processing. This may be NULL to indicate no route available. */ struct rte **rte; + + /* The old rta to be freed after filters are done. */ struct rta *old_rta; + + /* Cached pointer to ea_list */ struct ea_list **eattrs; struct linpool *pool; struct buffer buf; int flags; -}; +} filter_state; void (*bt_assert_hook)(int result, const struct f_line_item *assert); @@ -239,7 +244,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) * copied). * * The returned rte may reuse the (possibly cached, cloned) rta, or - * (if rta was modificied) contains a modified uncached rta, which + * (if rta was modified) contains a modified uncached rta, which * uses parts allocated from @tmp_pool and parts shared from original * rta. There is one exception - if @rte is rw but contains a cached * rta and that is modified, rta in returned rte is also cached. @@ -261,38 +266,47 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i int rte_cow = ((*rte)->flags & REF_COW); DBG( "Running filter `%s'...", filter->name ); - struct filter_state fs = { + /* Initialize the filter state */ + filter_state = (struct filter_state) { .rte = rte, .pool = tmp_pool, .flags = flags, }; - LOG_BUFFER_INIT(fs.buf); + LOG_BUFFER_INIT(filter_state.buf); - enum filter_return fret = interpret(&fs, filter->root, NULL); + /* Run the interpreter itself */ + enum filter_return fret = interpret(&filter_state, filter->root, NULL); - if (fs.old_rta) { + if (filter_state.old_rta) { /* - * Cached rta was modified and fs->rte contains now an uncached one, + * Cached rta was modified and filter_state->rte contains now an uncached one, * sharing some part with the cached one. The cached rta should - * be freed (if rte was originally COW, fs->old_rta is a clone + * be freed (if rte was originally COW, filter_state->old_rta is a clone * obtained during rte_cow()). * * This also implements the exception mentioned in f_run() * description. The reason for this is that rta reuses parts of - * fs->old_rta, and these may be freed during rta_free(fs->old_rta). + * filter_state->old_rta, and these may be freed during rta_free(filter_state->old_rta). * This is not the problem if rte was COW, because original rte * also holds the same rta. */ - if (!rte_cow) - (*fs.rte)->attrs = rta_lookup((*fs.rte)->attrs); + if (!rte_cow) { + /* Cache the new attrs */ + (*filter_state.rte)->attrs = rta_lookup((*filter_state.rte)->attrs); - rta_free(fs.old_rta); + /* Drop cached ea_list pointer */ + filter_state.eattrs = NULL; + } + + /* Uncache the old attrs and drop the pointer as it is invalid now. */ + rta_free(filter_state.old_rta); + filter_state.old_rta = NULL; } - + /* Process the filter output, log it and return */ if (fret < F_ACCEPT) { - if (!(fs.flags & FF_SILENT)) + if (!(filter_state.flags & FF_SILENT)) log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter_name(filter)); return F_ERROR; } @@ -300,49 +314,72 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i return fret; } -/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */ +/** + * f_eval_rte – run a filter line for an uncached route + * @expr: filter line to run + * @rte: route being filtered, may be modified + * @tmp_pool: all filter allocations go from this pool + * + * This specific filter entry point runs the given filter line + * (which must not have any arguments) on the given route. + * + * The route MUST NOT have REF_COW set and its attributes MUST NOT + * be cached by rta_lookup(). + */ enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) { - - struct filter_state fs = { + filter_state = (struct filter_state) { .rte = rte, .pool = tmp_pool, }; - LOG_BUFFER_INIT(fs.buf); + LOG_BUFFER_INIT(filter_state.buf); - /* Note that in this function we assume that rte->attrs is private / uncached */ - return interpret(&fs, expr, NULL); + ASSERT(!((*rte)->flags & REF_COW)); + ASSERT(!rta_is_cached((*rte)->attrs)); + + return interpret(&filter_state, expr, NULL); } +/* + * f_eval – get a value of a term + * @expr: filter line containing the term + * @tmp_pool: long data may get allocated from this pool + * @pres: here the output will be stored + */ enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) { - struct filter_state fs = { + filter_state = (struct filter_state) { .pool = tmp_pool, }; - LOG_BUFFER_INIT(fs.buf); + LOG_BUFFER_INIT(filter_state.buf); - enum filter_return fret = interpret(&fs, expr, pres); + enum filter_return fret = interpret(&filter_state, expr, pres); return fret; } +/* + * f_eval_int – get an integer value of a term + * Called internally from the config parser, uses its internal memory pool + * for allocations. Do not call in other cases. + */ uint f_eval_int(const struct f_line *expr) { /* Called independently in parse-time to eval expressions */ - struct filter_state fs = { + filter_state = (struct filter_state) { .pool = cfg_mem, }; struct f_val val; - LOG_BUFFER_INIT(fs.buf); + LOG_BUFFER_INIT(filter_state.buf); - if (interpret(&fs, expr, &val) > F_RETURN) + if (interpret(&filter_state, expr, &val) > F_RETURN) cf_error("Runtime error while evaluating expression"); if (val.type != T_INT) @@ -351,6 +388,9 @@ f_eval_int(const struct f_line *expr) return val.val.i; } +/* + * f_eval_buf – get a value of a term and print it to the supplied buffer + */ enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf) { From 96d757c13fe4b2e21b265275af9ac7d1e2c3f075 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Tue, 21 May 2019 16:33:37 +0000 Subject: [PATCH 53/88] Filter: Store variables and function arguments on stack --- conf/conf.h | 3 +- conf/confbase.Y | 2 +- filter/config.Y | 140 ++++++++++++++++++------------------------- filter/data.h | 4 +- filter/decl.m4 | 3 +- filter/f-inst.c | 93 ++++++++++------------------ filter/f-inst.h | 3 +- filter/f-util.c | 22 ------- filter/filter.c | 44 ++++++++------ filter/filter_test.c | 3 +- filter/test.conf | 3 +- 11 files changed, 125 insertions(+), 195 deletions(-) diff --git a/conf/conf.h b/conf/conf.h index f14c0e21..d88d9a44 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -116,7 +116,8 @@ struct symbol { const struct filter *filter; /* For SYM_FILTER */ struct rtable_config *table; /* For SYM_TABLE */ struct f_dynamic_attr *attribute; /* For SYM_ATTRIBUTE */ - struct f_val *val; /* For SYM_CONSTANT or SYM_VARIABLE */ + struct f_val *val; /* For SYM_CONSTANT */ + uint offset; /* For SYM_VARIABLE */ }; char name[0]; diff --git a/conf/confbase.Y b/conf/confbase.Y index e104e54f..9978aec8 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -70,7 +70,7 @@ CF_DECLS struct f_dynamic_attr fda; struct f_static_attr fsa; struct f_lval flv; - const struct f_line *fl; + struct f_line *fl; const struct filter *f; struct f_tree *e; struct f_trie *trie; diff --git a/filter/config.Y b/filter/config.Y index 3eccc3ed..5f9b8356 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -15,6 +15,8 @@ CF_HDR CF_DEFINES +static uint decls_count; + static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } @@ -398,8 +400,8 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const struct f_inst *setter, *getter, *checker; switch (lval->type) { case F_LVAL_VARIABLE: - setter = f_new_inst(FI_SET, expr, lval->sym); - getter = f_new_inst(FI_VARIABLE, lval->sym); + setter = f_new_inst(FI_VAR_SET, expr, lval->sym); + getter = f_new_inst(FI_VAR_GET, lval->sym); break; case F_LVAL_PREFERENCE: setter = f_new_inst(FI_PREF_SET, expr); @@ -446,14 +448,14 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc THEN %nonassoc ELSE -%type cmds_int function_body declsn function_params -%type term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls +%type cmds_int +%type term block cmd cmds constant constructor print_one print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter where_filter -%type filter_body +%type filter_body function_body %type lvalue -%type type +%type type function_params %type ec_kind %type break_command %type cnum @@ -553,43 +555,24 @@ type: } ; -one_decl: - type CF_SYM_VOID { - struct f_val * val = cfg_alloc(sizeof(struct f_val)); - val->type = T_VOID; - $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val, val); - DBG( "New variable %s type %x\n", $2->name, $1 ); - $$ = f_new_inst(FI_SET, NULL, $2); - } - ; - -/* Decls with ';' at the end. Beware; these are reversed. */ -decls: /* EMPTY */ { $$ = NULL; } - | one_decl ';' decls { - $$ = $1; - $$->next = $3; - } +/* Declarations with ';' at the end */ +decls: + /* EMPTY */ + | declsn ';' ; /* Declarations that have no ';' at the end. */ -declsn: one_decl { $$[0] = $$[1] = $1; } - | one_decl ';' declsn { - $3[1]->next = $1; - $$[1] = $3[1] = $1; - $$[0] = $3[0]; +declsn: + type CF_SYM_VOID { + cf_define_symbol($2, SYM_VARIABLE | $1, offset, decls_count++); + } + | declsn ';' type CF_SYM_VOID { + if (decls_count >= 0xff) cf_error("Too many declarations, at most 255 allowed"); + cf_define_symbol($4, SYM_VARIABLE | $3, offset, decls_count++); } ; -filter_body: - function_body { - if ($1[0]) { - const struct f_inst *inst[2] = { $1[0], $1[1] }; - $$ = f_postfixify_concat(inst, 2); - } - else - $$ = f_postfixify($1[1]); - } - ; +filter_body: { decls_count = 0; } function_body { $$ = $2; } ; filter: CF_SYM_KNOWN { @@ -611,14 +594,14 @@ where_filter: ; function_params: - '(' declsn ')' { $$[0] = $2[0]; $$[1] = $2[1]; } - | '(' ')' { $$[0] = $$[1] = NULL; } + '(' declsn ')' { $$ = decls_count; } + | '(' ')' { $$ = 0; } ; function_body: decls '{' cmds '}' { - $$[0] = $1 ? f_clear_local_vars($1) : NULL; - $$[1] = $3; + $$ = f_postfixify($3); + $$->vars = decls_count; } ; @@ -627,33 +610,11 @@ function_def: FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope($2); + decls_count = 0; } function_params function_body { - const struct f_inst *catlist[4]; - uint count = 0; - - /* Argument setters */ - if ($4[0]) - catlist[count++] = $4[0]; - - /* Local var clearers */ - if ($5[0]) - catlist[count++] = $5[0]; - - /* Return void if no return is needed */ - catlist[count++] = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); - - /* Function body itself */ - if ($5[1]) - catlist[count++] = $5[1]; - - struct f_line *fl = f_postfixify_concat(catlist, count); - - fl->args = 0; - for (const struct f_inst *arg = $4[0]; arg; arg = arg->next) - fl->args++; - - $2->function = fl; - + $5->vars -= $4; + $5->args = $4; + $2->function = $5; cf_pop_scope(); } ; @@ -862,9 +823,33 @@ constructor: ; +/* This generates the function_call variable list backwards. */ +var_list: /* EMPTY */ { $$ = NULL; } + | term { $$ = $1; } + | var_list ',' term { $$ = $3; $$->next = $1; } + function_call: CF_SYM_KNOWN '(' var_list ')' { - $$ = f_new_inst(FI_CALL, $1, $3); + if ($1->class != SYM_FUNCTION) + cf_error("You can't call something which is not a function. Really."); + + struct f_inst *fc = f_new_inst(FI_CALL, $1); + uint args = 0; + while ($3) { + args++; + struct f_inst *tmp = $3->next; + $3->next = fc; + + fc = $3; + $3 = tmp; + } + + if (args != $1->function->args) + cf_error("Function call '%s' got %u arguments, need %u arguments.", + $1->name, args, $1->function->args); + + $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); + $$->next = fc; } ; @@ -872,8 +857,10 @@ symbol_value: CF_SYM_KNOWN { switch ($1->class) { case SYM_CONSTANT_RANGE: + $$ = f_new_inst(FI_CONSTANT_DEFINED, $1); + break; case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VARIABLE, $1); + $$ = f_new_inst(FI_VAR_GET, $1); break; case SYM_ATTRIBUTE: $$ = f_new_inst(FI_EA_GET, *$1->attribute); @@ -988,19 +975,6 @@ print_list: /* EMPTY */ { $$ = NULL; } } ; -var_listn: term { - $$ = $1; - } - | term ',' var_listn { - $$ = $1; - $$->next = $3; - } - ; - -var_list: /* EMPTY */ { $$ = NULL; } - | var_listn { $$ = $1; } - ; - cmd: IF term THEN block { $$ = f_new_inst(FI_CONDITION, $2, $4, NULL); @@ -1011,7 +985,7 @@ cmd: | CF_SYM_KNOWN '=' term ';' { switch ($1->class) { case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_SET, $3, $1); + $$ = f_new_inst(FI_VAR_SET, $3, $1); break; case SYM_ATTRIBUTE: $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); diff --git a/filter/data.h b/filter/data.h index 6ef2024f..6973008f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -17,8 +17,8 @@ /* Internal types */ enum f_type { -/* Do not use type of zero, that way we'll see errors easier. */ - T_VOID = 1, +/* Nothing. Simply nothing. */ + T_VOID = 0, /* User visible types, which fit in int */ T_INT = 0x10, diff --git a/filter/decl.m4 b/filter/decl.m4 index bdd59f20..c9b5c8c5 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -209,6 +209,7 @@ do { estk.item[estk.cnt].pos = 0; estk.item[estk.cnt].line = $1; estk.item[estk.cnt].ventry = vstk.cnt; + estk.item[estk.cnt].vbase = estk.item[estk.cnt-1].vbase; estk.item[estk.cnt].emask = 0; estk.cnt++; } while (0)m4_dnl @@ -377,7 +378,7 @@ FID_WR_PUT(4) /* Filter instruction structure for config */ struct f_inst { - const struct f_inst *next; /* Next instruction */ + struct f_inst *next; /* Next instruction */ enum f_instruction_code fi_code; /* Instruction code */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ diff --git a/filter/f-inst.c b/filter/f-inst.c index d6c292b6..4a4f6016 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -261,23 +261,28 @@ } /* Set to indirect value prepared in v1 */ - INST(FI_SET, 1, 0) { + INST(FI_VAR_SET, 1, 0) { ARG_ANY(2); SYMBOL(1); 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)) - { - *(sym->val) = (struct f_val) { + v1 = (struct f_val) { .type = T_QUAD, .val.i = ipa_to_u32(v1.val.ip), - }; - break; - } - runtime( "Assigning to variable of incompatible type" ); + }; + else + runtime( "Assigning to variable of incompatible type" ); } - *(sym->val) = v1; + + vstk.val[curline.vbase + sym->offset] = v1; + } + + INST(FI_VAR_GET, 0, 1) { + SYMBOL(1); + res = vstk.val[curline.vbase + sym->offset]; + RESULT_OK; } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -301,7 +306,7 @@ res = whati->val; RESULT_OK; } - INST(FI_VARIABLE, 0, 1) { + INST(FI_CONSTANT_DEFINED, 0, 1) { FID_STRUCT_IN const struct symbol *sym; FID_LINE_IN @@ -314,18 +319,9 @@ FID_POSTFIXIFY_BODY item->valp = (item->sym = what->sym)->val; FID_SAME_BODY - if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0; + if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0; FID_DUMP_BODY - switch (item->sym->class) { - case SYM_CONSTANT_RANGE: - debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); - break; - case SYM_VARIABLE_RANGE: - debug("%svariable %s with current value %s\n", INDENT, item->sym->name, val_dump(item->valp)); - break; - default: - bug("Symbol %s of type %d doesn't reference a value", item->sym->name, item->sym->class); - } + debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); FID_ALL res = *whati->valp; @@ -768,56 +764,31 @@ else runtime("Can't return non-bool from non-function"); - /* Set the value stack position */ - vstk.cnt = estk.item[estk.cnt].ventry; + /* Set the value stack position, overwriting the former implicit void */ + vstk.cnt = estk.item[estk.cnt].ventry - 1; /* Copy the return value */ RESULT_VAL(vstk.val[retpos]); } INST(FI_CALL, 0, 1) { - FID_LINE_IN - const struct f_line *args; - const struct f_line *body; - struct symbol *sym; - FID_STRUCT_IN - struct symbol *sym; - const struct f_inst *args; - FID_NEW_ARGS - , struct symbol * sym - , const struct f_inst *args - FID_NEW_BODY - if (sym->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); + SYMBOL; - uint count = 0; - for (const struct f_inst *inst = args; inst; inst = inst->next) - count++; - - if (count != sym->function->args) - cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->function->args, count); - - what->sym = sym; - what->args = args; - FID_DUMP_BODY - debug("%scalling %s with following args\n", INDENT, item->sym->name); - f_dump_line(item->args, indent + 1); - FID_POSTFIXIFY_BODY - item->args = f_postfixify(what->args); - item->body = (item->sym = what->sym)->function; - FID_SAME_BODY - /* To be done better */ - if (strcmp(f1->sym->name, f2->sym->name)) return 0; - if (!f_same(f1->args, f2->args)) return 0; - if (!f_same(f1->body, f2->body)) return 0; - FID_ALL - - /* First push the body on stack */ - LINEX(whati->body); + /* Push the body on stack */ + LINEX(sym->function); curline.emask |= FE_RETURN; + + /* Before this instruction was called, there was the T_VOID + * automatic return value pushed on value stack and also + * sym->function->args function arguments. Setting the + * vbase to point to first argument. */ + ASSERT(curline.ventry >= sym->function->args); + curline.ventry -= sym->function->args; + curline.vbase = curline.ventry; - /* Then push the arguments */ - LINEX(whati->args); + /* Storage for local variables */ + memset(&(vstk.val[vstk.cnt]), 0, sizeof(struct f_val) * sym->function->vars); + vstk.cnt += sym->function->vars; } INST(FI_DROP_RESULT, 1, 0) { diff --git a/filter/f-inst.h b/filter/f-inst.h index 1e2d63a2..21cec454 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -63,13 +63,12 @@ enum f_instruction_flags { /* Convert the instruction back to the enum name */ const char *f_instruction_name(enum f_instruction_code fi); -struct f_inst *f_clear_local_vars(struct f_inst *decls); - /* Filter structures for execution */ /* Line of instructions to be unconditionally executed one after another */ struct f_line { uint len; /* Line length */ u8 args; /* Function: Args required */ + u8 vars; struct f_line_item items[0]; /* The items themselves */ }; diff --git a/filter/f-util.c b/filter/f-util.c index 35944b2c..79201fba 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -30,11 +30,6 @@ filter_name(const struct filter *filter) return filter->sym->name; } -void f_inst_next(struct f_inst *first, const struct f_inst *append) -{ - first->next = append; -} - struct filter *f_new_where(const struct f_inst *where) { struct f_inst acc = { @@ -67,23 +62,6 @@ struct filter *f_new_where(const struct f_inst *where) return f; } -struct f_inst *f_clear_local_vars(struct f_inst *decls) -{ - /* Prepend instructions to clear local variables */ - struct f_inst *head = NULL; - - for (const struct f_inst *si = decls; si; si = si->next) { - struct f_inst *cur = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); - if (head) - f_inst_next(cur, head); - else - f_inst_next(cur, si); - head = cur; /* The first FI_CONSTANT put there */ - } - - return head; -} - #define CA_KEY(n) n->name, n->fda.type #define CA_NEXT(n) n->next #define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb)) diff --git a/filter/filter.c b/filter/filter.c index 50d9414b..dbc2376b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -135,6 +135,8 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; static enum filter_return interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) { + /* No arguments allowed */ + ASSERT(line->args == 0); #define F_VAL_STACK_MAX 4096 /* Value stack for execution */ @@ -145,8 +147,12 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) /* The stack itself is intentionally kept as-is for performance reasons. * Do NOT rewrite this to initialization by struct literal. It's slow. - */ - vstk.cnt = 0; + * + * Reserving space for local variables. */ + + vstk.cnt = line->vars; + memset(vstk.val, 0, sizeof(struct f_val) * line->vars); + #define F_EXEC_STACK_MAX 4096 /* Exception bits */ @@ -160,6 +166,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) const struct f_line *line; /* The line that is being executed */ uint pos; /* Instruction index in the line */ uint ventry; /* Value stack depth on entry */ + uint vbase; /* Where to index variable positions from */ enum f_exception emask; /* Exception mask */ } item[F_EXEC_STACK_MAX]; uint cnt; /* Current stack size; 0 for empty */ @@ -181,7 +188,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) while (curline.pos < curline.line->len) { const struct f_line_item *what = &(curline.line->items[curline.pos++]); - switch (what->fi_code) { #define res vstk.val[vstk.cnt] #define v1 vstk.val[vstk.cnt] @@ -207,26 +213,28 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #undef ACCESS_EATTRS } } + + /* End of current line. Drop local variables before exiting. */ + vstk.cnt -= curline.line->vars; + vstk.cnt -= curline.line->args; estk.cnt--; } - switch (vstk.cnt) { - case 0: - if (val) { - log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack"); - return F_ERROR; - } - return F_NOP; - case 1: - if (val) { - *val = vstk.val[0]; - return F_NOP; - } - /* fallthrough */ - default: - log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt); + if (vstk.cnt == 0) { + if (val) { + log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack"); return F_ERROR; + } + return F_NOP; } + + if (val && (vstk.cnt == 1)) { + *val = vstk.val[0]; + return F_NOP; + } + + log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt); + return F_ERROR; } diff --git a/filter/filter_test.c b/filter/filter_test.c index d0dd281a..3abe095b 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -56,8 +56,7 @@ run_function(const void *arg) } linpool *tmp = lp_new_default(&root_pool); - struct f_val res; - enum filter_return fret = f_eval(t->fn, tmp, &res); + enum filter_return fret = f_eval(t->fn, tmp, NULL); rfree(tmp); return (fret < F_REJECT); diff --git a/filter/test.conf b/filter/test.conf index ba25a34b..9abd76f3 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -7,8 +7,7 @@ router id 62.168.0.1; /* We have to setup any protocol */ -protocol static { ipv4; } - +protocol device { } From 23e3b1e6652bac4a003a7eb1e074bdaf7ebb4900 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Wed, 22 May 2019 15:16:32 +0000 Subject: [PATCH 54/88] Filter: Some people can't pronounce "postfixify" correctly. Let's try "linearize" instead. This is just a naming change. --- conf/confbase.Y | 4 ++-- filter/config.Y | 14 +++++++------- filter/decl.m4 | 30 +++++++++++++++--------------- filter/f-inst.c | 8 ++++---- filter/f-inst.h | 8 ++++---- filter/f-util.c | 2 +- nest/config.Y | 4 ++-- proto/static/config.Y | 2 +- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index 9978aec8..bcfd3f1a 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -147,14 +147,14 @@ conf: definition ; definition: DEFINE CF_SYM_VOID '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); - if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); + if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); } ; expr: NUM - | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } + | '(' term ')' { $$ = f_eval_int(f_linearize($2)); } | CF_SYM_KNOWN { if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected"); $$ = SYM_VAL($1).i; } diff --git a/filter/config.Y b/filter/config.Y index 5f9b8356..3898748c 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -481,7 +481,7 @@ filter_def: conf: filter_eval ; filter_eval: - EVAL term { f_eval_int(f_postfixify($2)); } + EVAL term { f_eval_int(f_linearize($2)); } ; conf: custom_attr ; @@ -600,7 +600,7 @@ function_params: function_body: decls '{' cmds '}' { - $$ = f_postfixify($3); + $$ = f_linearize($3); $$->vars = decls_count; } ; @@ -661,7 +661,7 @@ set_atom: | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); + if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } | CF_SYM_KNOWN { @@ -673,13 +673,13 @@ set_atom: switch_atom: NUM { $$.type = T_INT; $$.val.i = $1; } - | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); } + | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); } | fipa { $$ = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } ; cnum: - term { $$ = f_eval_int(f_postfixify($1)); } + term { $$ = f_eval_int(f_linearize($1)); } pair_item: '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } @@ -766,7 +766,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } | switch_body switch_items ':' cmds { /* Fill data fields */ struct f_tree *t; - struct f_line *line = f_postfixify($4); + struct f_line *line = f_linearize($4); for (t = $2; t; t = t->left) t->data = line; $$ = f_merge_items($1, $2); @@ -775,7 +775,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } struct f_tree *t = f_new_tree(); t->from.type = t->to.type = T_VOID; t->right = t; - t->data = f_postfixify($3); + t->data = f_linearize($3); $$ = f_merge_items($1, t); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index c9b5c8c5..d8497535 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -12,7 +12,7 @@ m4_divert(-1)m4_dnl # 5 enum fi_code to string # 6 dump line item # 7 dump line item callers -# 8 postfixify +# 8 linearize # 9 same (filter comparator) # 1 union in struct f_inst # 3 constructors @@ -23,7 +23,7 @@ m4_divert(-1)m4_dnl # 102 constructor arguments # 103 constructor body # 104 dump line item content -# 105 postfixify body +# 105 linearize body # 106 comparator body # 107 struct f_line_item content # 108 interpreter body @@ -45,7 +45,7 @@ m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') -m4_define(FID_POSTFIXIFY, `FID_ZONE(8, Postfixify)') +m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') m4_define(FID_SAME, `FID_ZONE(9, Comparison)') m4_define(FID_INTERPRET, `FID_ZONE(10, Interpret)') @@ -53,7 +53,7 @@ m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') -m4_define(FID_POSTFIXIFY_BODY, `m4_divert(105)m4_define([[FID_POSTFIXIFY_BODY_EXISTS]])') +m4_define(FID_LINEARIZE_BODY, `m4_divert(105)m4_define([[FID_LINEARIZE_BODY_EXISTS]])') m4_define(FID_SAME_BODY, `m4_divert(106)') m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_INTERPRET_BODY, `m4_divert(108)') @@ -112,7 +112,7 @@ m4_undivert(104) } FID_ALL_TARGETS -FID_POSTFIXIFY +FID_LINEARIZE case INST_NAME(): { #define what (&(what_->i_]]INST_NAME()[[)) #define item (&(dest->items[pos].i_]]INST_NAME()[[)) @@ -123,7 +123,7 @@ case INST_NAME(): { dest->items[pos].lineno = what_->lineno; break; } -m4_undefine([[FID_POSTFIXIFY_BODY_EXISTS]]) +m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) FID_SAME case INST_NAME(): @@ -170,7 +170,7 @@ FID_NEW_ARGS FID_NEW_BODY what->$2 = $2; m4_ifelse($3,,,[[ -FID_POSTFIXIFY_BODY +FID_LINEARIZE_BODY item->$3 = what->$2; ]]) m4_ifelse($4,,,[[ @@ -195,8 +195,8 @@ FID_NEW_ARGS FID_NEW_BODY what->f$1 = f$1; for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; -FID_POSTFIXIFY_BODY -pos = postfixify(dest, what->f$1, pos);m4_dnl +FID_LINEARIZE_BODY +pos = linearize(dest, what->f$1, pos);m4_dnl FID_ALL()') m4_define(ARG, `ARG_ANY($1) @@ -226,8 +226,8 @@ FID_NEW_BODY what->f$1 = f$1; FID_DUMP_BODY f_dump_line(item->fl$1, indent + 1); -FID_POSTFIXIFY_BODY -item->fl$1 = f_postfixify(what->f$1); +FID_LINEARIZE_BODY +item->fl$1 = f_linearize(what->f$1); FID_SAME_BODY if (!f_same(f1->fl$1, f2->fl$1)) return 0; FID_INTERPRET_BODY @@ -310,9 +310,9 @@ FID_WR_PUT(7) debug("%sFilter line %p dump done\n", INDENT, dest); } -/* Postfixify */ +/* Linearize */ static uint -postfixify(struct f_line *dest, const struct f_inst *what_, uint pos) +linearize(struct f_line *dest, const struct f_inst *what_, uint pos) { for ( ; what_; what_ = what_->next) { switch (what_->fi_code) { @@ -324,7 +324,7 @@ FID_WR_PUT(8) } struct f_line * -f_postfixify_concat(const struct f_inst * const inst[], uint count) +f_linearize_concat(const struct f_inst * const inst[], uint count) { uint len = 0; for (uint i=0; ilen = postfixify(out, inst[i], out->len); + out->len = linearize(out, inst[i], out->len); #if DEBUGGING f_dump_line(out, 0); diff --git a/filter/f-inst.c b/filter/f-inst.c index 4a4f6016..d0bfa95b 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -295,7 +295,7 @@ , const struct f_val val FID_NEW_BODY what->val = val; - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY item->val = what->val; FID_SAME_BODY if (!val_same(&(f1->val), &(f2->val))) return 0; @@ -316,7 +316,7 @@ , const struct symbol *sym FID_NEW_BODY what->sym = sym; - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY item->valp = (item->sym = what->sym)->val; FID_SAME_BODY if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0; @@ -339,14 +339,14 @@ LINE(3,1); } INST(FI_PRINT_AND_DIE, 0, 0) { - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY { uint opos = pos; FID_ALL ARG_ANY(1); - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY if (opos < pos) dest->items[pos].flags |= FIF_PRINTED; } diff --git a/filter/f-inst.h b/filter/f-inst.h index 21cec454..f0dcec64 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -17,7 +17,7 @@ * translates into f_new_inst_FI_code(...) and the types are checked in * compile time. * - * 2 Postfixify before interpreting + * 2 Linearize before interpreting * The infix tree is always interpreted in the same order. Therefore we * sort the instructions one after another into struct f_line. Results * and arguments of these instructions are implicitly put on a value @@ -73,9 +73,9 @@ struct f_line { }; /* Convert the f_inst infix tree to the f_line structures */ -struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint count); -static inline struct f_line *f_postfixify(const struct f_inst *root) -{ return f_postfixify_concat(&root, 1); } +struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count); +static inline struct f_line *f_linearize(const struct f_inst *root) +{ return f_linearize_concat(&root, 1); } void f_dump_line(const struct f_line *, uint indent); diff --git a/filter/f-util.c b/filter/f-util.c index 79201fba..5500f282 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -58,7 +58,7 @@ struct filter *f_new_where(const struct f_inst *where) }; struct filter *f = cfg_allocz(sizeof(struct filter)); - f->root = f_postfixify(&i); + f->root = f_linearize(&i); return f; } diff --git a/nest/config.Y b/nest/config.Y index fe642489..e4dedc66 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -112,7 +112,7 @@ rtrid: idval: NUM { $$ = $1; } - | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); } + | '(' term ')' { $$ = f_eval_int(f_linearize($2)); } | IP4 { $$ = ip4_to_u32($1); } | CF_SYM_KNOWN { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) @@ -733,7 +733,7 @@ CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { protos_dump_all(); cli_msg(0, ""); } ; CF_CLI(EVAL, term, , [[Evaluate an expression]]) -{ cmd_eval(f_postfixify($2)); } ; +{ cmd_eval(f_linearize($2)); } ; CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]]) CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [], [[Control echoing of log messages]]) { diff --git a/proto/static/config.Y b/proto/static/config.Y index 3e9ac578..6e410879 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -40,7 +40,7 @@ static_route_finish(void) if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest) cf_error("Unexpected or missing nexthop/type"); - this_srt->cmds = f_postfixify(this_srt_cmds); + this_srt->cmds = f_linearize(this_srt_cmds); } CF_DECLS From 6479e403ef7398f48c0e1c0f1a71aa112938a357 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Thu, 23 May 2019 11:27:24 +0000 Subject: [PATCH 55/88] Filters: If somebody doesn't like _Thread_local, don't fail for now, just be a little slower. When the parallel execution comes into place, we'll likely enforce this C11 feature. It's much simpler and also faster than pthread_[sg]etspecific(). --- aclocal.m4 | 21 ++++++++++++++++++++- configure.ac | 5 +++++ filter/filter.c | 41 ++++++++++++++++++++++++----------------- lib/birdlib.h | 6 ++++++ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/aclocal.m4 b/aclocal.m4 index 0044adf9..746d5df5 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,25 @@ dnl ** Additional Autoconf tests for BIRD configure script dnl ** (c) 1999 Martin Mares +AC_DEFUN([BIRD_CHECK_THREAD_LOCAL], +[ + AC_CACHE_CHECK( + [whether _Thread_local is known], + [bird_cv_thread_local], + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [ + _Thread_local static int x = 42; + ], + [] + ) + ], + [bird_cv_thread_local=yes], + [bird_cv_thread_local=no] + ) + ) +]) + AC_DEFUN([BIRD_CHECK_PTHREADS], [ bird_tmp_cflags="$CFLAGS" @@ -134,7 +153,7 @@ AC_DEFUN([BIRD_CHECK_ANDROID_LOG], AC_DEFUN([BIRD_CHECK_LTO], [ bird_tmp_cflags="$CFLAGS" - bird_tmp_ldflags="$CFLAGS" + bird_tmp_ldflags="$LDFLAGS" CFLAGS="-flto" LDFLAGS="-flto" diff --git a/configure.ac b/configure.ac index 58fdc7fe..5ec75359 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,11 @@ if test -z "$GCC" ; then AC_MSG_ERROR([This program requires the GNU C Compiler.]) fi +BIRD_CHECK_THREAD_LOCAL +if test "$bird_cv_thread_local" = yes ; then + AC_DEFINE([HAVE_THREAD_LOCAL], [1], [Define to 1 if _Thread_local is available]) +fi + if test "$enable_pthreads" != no ; then BIRD_CHECK_PTHREADS diff --git a/filter/filter.c b/filter/filter.c index dbc2376b..65572583 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -51,7 +51,7 @@ #include "filter/data.h" /* Internal filter state, to be allocated on stack when executing filters */ -_Thread_local struct filter_state { +struct filter_state { /* The route we are processing. This may be NULL to indicate no route available. */ struct rte **rte; @@ -63,7 +63,14 @@ _Thread_local struct filter_state { struct linpool *pool; struct buffer buf; int flags; -} filter_state; +}; + +#if HAVE_THREAD_LOCAL +_Thread_local static struct filter_state filter_state; +#define FS_INIT(...) filter_state = (struct filter_state) { __VA_ARGS__ } +#else +#define FS_INIT(...) struct filter_state filter_state = { __VA_ARGS__ } +#endif void (*bt_assert_hook)(int result, const struct f_line_item *assert); @@ -275,11 +282,11 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i DBG( "Running filter `%s'...", filter->name ); /* Initialize the filter state */ - filter_state = (struct filter_state) { - .rte = rte, - .pool = tmp_pool, - .flags = flags, - }; + FS_INIT( + .rte = rte, + .pool = tmp_pool, + .flags = flags, + ); LOG_BUFFER_INIT(filter_state.buf); @@ -338,10 +345,10 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) { - filter_state = (struct filter_state) { - .rte = rte, - .pool = tmp_pool, - }; + FS_INIT( + .rte = rte, + .pool = tmp_pool, + ); LOG_BUFFER_INIT(filter_state.buf); @@ -360,9 +367,9 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) { - filter_state = (struct filter_state) { - .pool = tmp_pool, - }; + FS_INIT( + .pool = tmp_pool, + ); LOG_BUFFER_INIT(filter_state.buf); @@ -379,9 +386,9 @@ uint f_eval_int(const struct f_line *expr) { /* Called independently in parse-time to eval expressions */ - filter_state = (struct filter_state) { - .pool = cfg_mem, - }; + FS_INIT( + .pool = cfg_mem, + ); struct f_val val; diff --git a/lib/birdlib.h b/lib/birdlib.h index 6fcc202f..9743da32 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -73,6 +73,12 @@ static inline int u64_cmp(u64 i1, u64 i2) #define UNUSED __attribute__((unused)) #define PACKED __attribute__((packed)) +#ifdef HAVE_THREAD_LOCAL +#define THREAD_LOCAL _Thread_local +#else +#define THREAD_LOCAL +#endif + /* Microsecond time */ typedef s64 btime; From 1757a6fce5bd23c44cc5b72a042644c4abb744c8 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 29 May 2019 21:03:52 +0200 Subject: [PATCH 56/88] Filter: Stacks moved to thread-local storage if available. --- filter/decl.m4 | 16 ++++---- filter/f-inst.c | 28 ++++++------- filter/filter.c | 102 ++++++++++++++++++++++++------------------------ 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index d8497535..9934d0ba 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -137,7 +137,7 @@ break; FID_INTERPRET case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) -m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]]) +m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) m4_undivert(108) #undef whati break; @@ -206,12 +206,12 @@ FID_ALL()') m4_define(LINEX, `FID_INTERPRET_BODY do { - estk.item[estk.cnt].pos = 0; - estk.item[estk.cnt].line = $1; - estk.item[estk.cnt].ventry = vstk.cnt; - estk.item[estk.cnt].vbase = estk.item[estk.cnt-1].vbase; - estk.item[estk.cnt].emask = 0; - estk.cnt++; + fstk->estk[fstk->ecnt].pos = 0; + fstk->estk[fstk->ecnt].line = $1; + fstk->estk[fstk->ecnt].ventry = fstk->vcnt; + fstk->estk[fstk->ecnt].vbase = fstk->estk[fstk->ecnt-1].vbase; + fstk->estk[fstk->ecnt].emask = 0; + fstk->ecnt++; } while (0)m4_dnl FID_ALL()') @@ -236,7 +236,7 @@ do { if (whati->fl$1) { } } while(0)m4_dnl FID_ALL()') -m4_define(RESULT_OK, `FID_INTERPRET_BODY()vstk.cnt++FID_ALL()') +m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()') m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') diff --git a/filter/f-inst.c b/filter/f-inst.c index d0bfa95b..749e072c 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -156,12 +156,12 @@ what->count = len; FID_ALL - if (vstk.cnt < whati->count) /* TODO: make this check systematic */ + if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); for (uint i=0; icount; i++) { -#define pv vstk.val[vstk.cnt - whati->count + i] +#define pv fstk->vstk[fstk->vcnt - whati->count + i] switch (pv.type) { case T_PATH_MASK_ITEM: pm->item[i] = pv.val.pmi; @@ -177,7 +177,7 @@ } } - vstk.cnt -= whati->count; + fstk->vcnt -= whati->count; pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); @@ -276,12 +276,12 @@ runtime( "Assigning to variable of incompatible type" ); } - vstk.val[curline.vbase + sym->offset] = v1; + fstk->vstk[curline.vbase + sym->offset] = v1; } INST(FI_VAR_GET, 0, 1) { SYMBOL(1); - res = vstk.val[curline.vbase + sym->offset]; + res = fstk->vstk[curline.vbase + sym->offset]; RESULT_OK; } @@ -747,16 +747,16 @@ INST(FI_RETURN, 1, 1) { /* Acquire the return value */ ARG_ANY(1); - uint retpos = vstk.cnt; + uint retpos = fstk->vcnt; /* Drop every sub-block including ourselves */ - while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN)) + while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN)) ; /* Now we are at the caller frame; if no such, try to convert to accept/reject. */ - if (!estk.cnt) - if (vstk.val[retpos].type == T_BOOL) - if (vstk.val[retpos].val.i) + if (!fstk->ecnt) + if (fstk->vstk[retpos].type == T_BOOL) + if (fstk->vstk[retpos].val.i) return F_ACCEPT; else @@ -765,10 +765,10 @@ runtime("Can't return non-bool from non-function"); /* Set the value stack position, overwriting the former implicit void */ - vstk.cnt = estk.item[estk.cnt].ventry - 1; + fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1; /* Copy the return value */ - RESULT_VAL(vstk.val[retpos]); + RESULT_VAL(fstk->vstk[retpos]); } INST(FI_CALL, 0, 1) { @@ -787,8 +787,8 @@ curline.vbase = curline.ventry; /* Storage for local variables */ - memset(&(vstk.val[vstk.cnt]), 0, sizeof(struct f_val) * sym->function->vars); - vstk.cnt += sym->function->vars; + memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars); + fstk->vcnt += sym->function->vars; } INST(FI_DROP_RESULT, 1, 0) { diff --git a/filter/filter.c b/filter/filter.c index 65572583..c651253c 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -50,8 +50,37 @@ #include "filter/f-inst.h" #include "filter/data.h" + +/* Exception bits */ +enum f_exception { + FE_RETURN = 0x1, +}; + + +struct filter_stack { + /* Value stack for execution */ +#define F_VAL_STACK_MAX 4096 + uint vcnt; /* Current value stack size; 0 for empty */ + uint ecnt; /* Current execute stack size; 0 for empty */ + + struct f_val vstk[F_VAL_STACK_MAX]; /* The stack itself */ + + /* Instruction stack for execution */ +#define F_EXEC_STACK_MAX 4096 + struct { + const struct f_line *line; /* The line that is being executed */ + uint pos; /* Instruction index in the line */ + uint ventry; /* Value stack depth on entry */ + uint vbase; /* Where to index variable positions from */ + enum f_exception emask; /* Exception mask */ + } estk[F_EXEC_STACK_MAX]; +}; + /* Internal filter state, to be allocated on stack when executing filters */ struct filter_state { + /* Stacks needed for execution */ + struct filter_stack *stack; + /* The route we are processing. This may be NULL to indicate no route available. */ struct rte **rte; @@ -67,9 +96,10 @@ struct filter_state { #if HAVE_THREAD_LOCAL _Thread_local static struct filter_state filter_state; -#define FS_INIT(...) filter_state = (struct filter_state) { __VA_ARGS__ } +_Thread_local static struct filter_stack filter_stack; +#define FS_INIT(...) filter_state = (struct filter_state) { .stack = &filter_stack, __VA_ARGS__ } #else -#define FS_INIT(...) struct filter_state filter_state = { __VA_ARGS__ } +#define FS_INIT(...) struct filter_state filter_state = { .stack = alloca(sizeof(struct filter_stack)), __VA_ARGS__ }; #endif void (*bt_assert_hook)(int result, const struct f_line_item *assert); @@ -145,61 +175,33 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) /* No arguments allowed */ ASSERT(line->args == 0); -#define F_VAL_STACK_MAX 4096 - /* Value stack for execution */ - struct f_val_stack { - uint cnt; /* Current stack size; 0 for empty */ - struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */ - } vstk; + /* Initialize the filter stack */ + struct filter_stack *fstk = fs->stack; - /* The stack itself is intentionally kept as-is for performance reasons. - * Do NOT rewrite this to initialization by struct literal. It's slow. - * - * Reserving space for local variables. */ - - vstk.cnt = line->vars; - memset(vstk.val, 0, sizeof(struct f_val) * line->vars); - -#define F_EXEC_STACK_MAX 4096 - - /* Exception bits */ - enum f_exception { - FE_RETURN = 0x1, - }; - - /* Instruction stack for execution */ - struct f_exec_stack { - struct { - const struct f_line *line; /* The line that is being executed */ - uint pos; /* Instruction index in the line */ - uint ventry; /* Value stack depth on entry */ - uint vbase; /* Where to index variable positions from */ - enum f_exception emask; /* Exception mask */ - } item[F_EXEC_STACK_MAX]; - uint cnt; /* Current stack size; 0 for empty */ - } estk; + fstk->vcnt = line->vars; + memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars); /* The same as with the value stack. Not resetting the stack for performance reasons. */ - estk.cnt = 1; - estk.item[0].line = line; - estk.item[0].pos = 0; + fstk->ecnt = 1; + fstk->estk[0].line = line; + fstk->estk[0].pos = 0; -#define curline estk.item[estk.cnt-1] +#define curline fstk->estk[fstk->ecnt-1] #if DEBUGGING debug("Interpreting line."); f_dump_line(line, 1); #endif - while (estk.cnt > 0) { + while (fstk->ecnt > 0) { while (curline.pos < curline.line->len) { const struct f_line_item *what = &(curline.line->items[curline.pos++]); switch (what->fi_code) { -#define res vstk.val[vstk.cnt] -#define v1 vstk.val[vstk.cnt] -#define v2 vstk.val[vstk.cnt + 1] -#define v3 vstk.val[vstk.cnt + 2] +#define res fstk->vstk[fstk->vcnt] +#define v1 fstk->vstk[fstk->vcnt] +#define v2 fstk->vstk[fstk->vcnt + 1] +#define v3 fstk->vstk[fstk->vcnt + 2] #define runtime(fmt, ...) do { \ if (!(fs->flags & FF_SILENT)) \ @@ -222,12 +224,12 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) } /* End of current line. Drop local variables before exiting. */ - vstk.cnt -= curline.line->vars; - vstk.cnt -= curline.line->args; - estk.cnt--; + fstk->vcnt -= curline.line->vars; + fstk->vcnt -= curline.line->args; + fstk->ecnt--; } - if (vstk.cnt == 0) { + if (fstk->vcnt == 0) { if (val) { log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack"); return F_ERROR; @@ -235,12 +237,12 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) return F_NOP; } - if (val && (vstk.cnt == 1)) { - *val = vstk.val[0]; + if (val && (fstk->vcnt == 1)) { + *val = fstk->vstk[0]; return F_NOP; } - log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt); + log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", fstk->vcnt); return F_ERROR; } From aa6c5f4d92f225452e432991671e7bdad185506a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 30 May 2019 14:42:54 +0200 Subject: [PATCH 57/88] Filter: Just a little comments in filter structure --- filter/filter.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/filter/filter.c b/filter/filter.c index c651253c..9b61c707 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -89,8 +89,14 @@ struct filter_state { /* Cached pointer to ea_list */ struct ea_list **eattrs; + + /* Linpool for adata allocation */ struct linpool *pool; + + /* Buffer for log output */ struct buffer buf; + + /* Filter execution flags */ int flags; }; From bd91338246c1ba40358243f1bdf5a6dbd3a29f35 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 31 May 2019 17:33:41 +0200 Subject: [PATCH 58/88] Filter: Dropped the setter instructions in favor of direct result storage. This should help filter performance a bit. --- filter/config.Y | 59 +++++++---- filter/data.c | 1 - filter/data.h | 8 ++ filter/decl.m4 | 69 ++++++++++++- filter/f-inst.c | 232 +++---------------------------------------- filter/f-inst.h | 1 - filter/filter.c | 254 +++++++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 364 insertions(+), 260 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 3898748c..f57575fc 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -21,9 +21,13 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } -#define f_generate_complex(fi_code, da, arg) \ - f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) - +#define f_generate_complex(fi_code, _da, arg) ({ \ + struct f_inst *fi = f_new_inst(fi_code, f_new_inst(FI_EA_GET, _da), arg); \ + fi->result.type = F_LVAL_EA; \ + fi->result.da = _da; \ + fi; \ +}) + /* * Sets and their items are during parsing handled as lists, linked * through left ptr. The first item in a list also contains a pointer @@ -184,7 +188,10 @@ f_generate_empty(struct f_dynamic_attr dyn) cf_error("Can't empty that attribute"); } - return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); + struct f_inst *fi = f_new_inst(FI_CONSTANT, empty); + fi->result.type = F_LVAL_EA; + fi->result.da = dyn; + return fi; } #if 0 @@ -397,31 +404,34 @@ assert_done(struct f_inst *expr, const char *start, const char *end) static struct f_inst * assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end) { - struct f_inst *setter, *getter, *checker; + struct f_inst *getter; switch (lval->type) { + case F_LVAL_STACK: + bug("This shall never happen"); + case F_LVAL_EXCEPTION: + bug("This shall never happen"); case F_LVAL_VARIABLE: - setter = f_new_inst(FI_VAR_SET, expr, lval->sym); getter = f_new_inst(FI_VAR_GET, lval->sym); break; case F_LVAL_PREFERENCE: - setter = f_new_inst(FI_PREF_SET, expr); getter = f_new_inst(FI_PREF_GET); break; case F_LVAL_SA: - setter = f_new_inst(FI_RTA_SET, expr, lval->sa); getter = f_new_inst(FI_RTA_GET, lval->sa); break; case F_LVAL_EA: - setter = f_new_inst(FI_EA_SET, expr, lval->da); getter = f_new_inst(FI_EA_GET, lval->da); break; - default: - bug("Unknown lval type"); } - checker = f_new_inst(FI_EQ, expr, getter); + struct f_inst *checker = f_new_inst(FI_EQ, expr, getter); + + struct f_inst *setter = cfg_alloc(sizeof(struct f_inst)); + *setter = *expr; + setter->next = checker; - + setter->result = *lval; + return assert_done(setter, start, end); } @@ -985,29 +995,40 @@ cmd: | CF_SYM_KNOWN '=' term ';' { switch ($1->class) { case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VAR_SET, $3, $1); + $3->result.type = F_LVAL_VARIABLE; + $3->result.sym = $1; break; case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); + $3->result.type = F_LVAL_EA; + $3->result.da = *$1->attribute; break; default: cf_error("Can't assign to symbol %s", $1->name); } + $$ = $3; } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); - $$ = f_new_inst(FI_RETURN, $2); + $2->result.type = F_LVAL_EXCEPTION; + $2->result.exception = FE_RETURN; + $$ = $2; } | dynamic_attr '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $3, $1); + $3->result.type = F_LVAL_EA; + $3->result.da = $1; + $$ = $3; } | static_attr '=' term ';' { if ($1.readonly) cf_error( "This static attribute is read-only."); - $$ = f_new_inst(FI_RTA_SET, $3, $1); + + $3->result.type = F_LVAL_SA; + $3->result.sa = $1; + $$ = $3; } | PREFERENCE '=' term ';' { - $$ = f_new_inst(FI_PREF_SET, $3); + $3->result.type = F_LVAL_PREFERENCE; + $$ = $3; } | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); diff --git a/filter/data.c b/filter/data.c index 912e2b00..cb759a59 100644 --- a/filter/data.c +++ b/filter/data.c @@ -525,4 +525,3 @@ val_dump(const struct f_val *v) { val_format(v, &b); return val_dump_buffer; } - diff --git a/filter/data.h b/filter/data.h index 6973008f..3718cea4 100644 --- a/filter/data.h +++ b/filter/data.h @@ -107,8 +107,15 @@ struct f_static_attr { int readonly:1; /* Don't allow writing */ }; +/* Exception bits */ +enum f_exception { + FE_RETURN = 0x1, +}; + /* Filter l-value type */ enum f_lval_type { + F_LVAL_STACK = 0, + F_LVAL_EXCEPTION, F_LVAL_VARIABLE, F_LVAL_PREFERENCE, F_LVAL_SA, @@ -119,6 +126,7 @@ enum f_lval_type { struct f_lval { enum f_lval_type type; union { + enum f_exception exception; const struct symbol *sym; struct f_dynamic_attr da; struct f_static_attr sa; diff --git a/filter/decl.m4 b/filter/decl.m4 index 9934d0ba..a1d625f3 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -119,8 +119,6 @@ case INST_NAME(): { m4_undivert(105) #undef what #undef item - dest->items[pos].fi_code = what_->fi_code; - dest->items[pos].lineno = what_->lineno; break; } m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) @@ -236,9 +234,29 @@ do { if (whati->fl$1) { } } while(0)m4_dnl FID_ALL()') -m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()') -m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') -m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') +m4_define(RESULT_PTR, ` +FID_INTERPRET_BODY + do { + enum filter_return fret = f_lval_set(fs, &(what->result), $1); + if (fret != F_NOP) return fret; + } while (0)m4_dnl +FID_ALL()') + +m4_define(RESULT, ` +FID_INTERPRET_BODY + do { + struct f_val res_ = { .type = $1, .val.$2 = $3 }; + RESULT_PTR(&res_); + } while (0)m4_dnl +FID_ALL()') + +m4_define(RESULT_VOID, ` +FID_INTERPRET_BODY + do { + struct f_val res_ = { .type = T_VOID }; + RESULT_PTR(&res_); + } while (0)m4_dnl +FID_ALL()') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') @@ -302,6 +320,16 @@ void f_dump_line(const struct f_line *dest, uint indent) for (uint i=0; ilen; i++) { const struct f_line_item *item = &dest->items[i]; debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); + + switch (item->result.type) { + case F_LVAL_STACK: debug("%son stack\n", INDENT); break; + case F_LVAL_EXCEPTION: debug("%s=>exception 0x%x\n", INDENT, item->result.exception); break; + case F_LVAL_VARIABLE: debug("%s=>%s\n", INDENT, item->result.sym->name); break; + case F_LVAL_PREFERENCE: debug("%s=>preference\n", INDENT); break; + case F_LVAL_SA: debug("%s=>sa\n", INDENT); break; + case F_LVAL_EA: debug("%s=>ea\n", INDENT); break; + } + switch (item->fi_code) { FID_WR_PUT(7) default: bug("Unknown instruction %x in f_dump_line", item->fi_code); @@ -318,6 +346,9 @@ linearize(struct f_line *dest, const struct f_inst *what_, uint pos) switch (what_->fi_code) { FID_WR_PUT(8) } + dest->items[pos].fi_code = what_->fi_code; + dest->items[pos].lineno = what_->lineno; + dest->items[pos].result = what_->result; pos++; } return pos; @@ -360,6 +391,32 @@ f_same(const struct f_line *fl1, const struct f_line *fl2) if (f1_->flags != f2_->flags) return 0; + if (f1_->result.type != f2_->result.type) return 0; + switch (f1_->result.type) { + case F_LVAL_STACK: + break; + case F_LVAL_EXCEPTION: + if (f1_->result.exception != f2_->result.exception) + return 0; + break; + case F_LVAL_VARIABLE: + if (strcmp(f1_->result.sym->name, f2_->result.sym->name)) + return 0; + if (f1_->result.sym->class != f2_->result.sym->class) + return 0; + break; + case F_LVAL_PREFERENCE: + break; + case F_LVAL_SA: + if (f1_->result.sa.sa_code != f2_->result.sa.sa_code) + return 0; + break; + case F_LVAL_EA: + if (f1_->result.da.ea_code != f2_->result.da.ea_code) + return 0; + break; + } + switch(f1_->fi_code) { FID_WR_PUT(9) } @@ -382,6 +439,7 @@ struct f_inst { enum f_instruction_code fi_code; /* Instruction code */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ + struct f_lval result; /* Destination */ union { FID_WR_PUT(1) }; @@ -392,6 +450,7 @@ struct f_line_item { enum f_instruction_code fi_code; /* What to do */ enum f_instruction_flags flags; /* Flags, instruction-specific */ uint lineno; /* Where */ + struct f_lval result; /* Destination */ union { FID_WR_PUT(2) }; diff --git a/filter/f-inst.c b/filter/f-inst.c index 749e072c..3be76d11 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -36,7 +36,7 @@ * m4_dnl ACCESS_RTE; this instruction needs route * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes * m4_dnl RESULT(type, union-field, value); putting this on value stack - * m4_dnl RESULT_OK; legalize what already is on the value stack + * m4_dnl RESULT_PTR(vptr); put what is pointed-to on the value stack * m4_dnl } * * Other code is just copied into the interpreter part. @@ -50,41 +50,37 @@ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i += v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i + v2.val.i); } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i -= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i - v2.val.i); } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i *= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i * v2.val.i); } INST(FI_DIVIDE, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); - res.val.i /= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i / v2.val.i); } INST(FI_AND, 1, 1) { ARG(1,T_BOOL); - if (res.val.i) + if (v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_PTR(&(v1)); } INST(FI_OR, 1, 1) { ARG(1,T_BOOL); - if (!res.val.i) + if (!v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_PTR(&(v1)); } INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); @@ -281,8 +277,7 @@ INST(FI_VAR_GET, 0, 1) { SYMBOL(1); - res = fstk->vstk[curline.vbase + sym->offset]; - RESULT_OK; + RESULT_PTR(&(fstk->vstk[curline.vbase + sym->offset])); } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -303,8 +298,7 @@ debug("%svalue %s\n", INDENT, val_dump(&item->val)); FID_ALL - res = whati->val; - RESULT_OK; + RESULT_PTR(&(whati->val)); } INST(FI_CONSTANT_DEFINED, 0, 1) { FID_STRUCT_IN @@ -324,8 +318,7 @@ debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); FID_ALL - res = *whati->valp; - RESULT_OK; + RESULT_PTR(whati->valp); } INST(FI_PRINT, 1, 0) { ARG_ANY(1); @@ -398,76 +391,6 @@ } } - INST(FI_RTA_SET, 1, 0) { - ACCESS_RTE; - ARG_ANY(1); - STATIC_ATTR; - if (sa.f_type != v1.type) - runtime( "Attempt to set static attribute to incompatible type" ); - - f_rta_cow(fs); - { - struct rta *rta = (*fs->rte)->attrs; - - switch (sa.sa_code) - { - case SA_FROM: - rta->from = v1.val.ip; - break; - - case SA_GW: - { - ip_addr ip = v1.val.ip; - neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); - if (!n || (n->scope == SCOPE_HOST)) - runtime( "Invalid gw address" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = ip; - rta->nh.iface = n->iface; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - break; - - case SA_SCOPE: - rta->scope = v1.val.i; - break; - - case SA_DEST: - { - int i = v1.val.i; - if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) - runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); - - rta->dest = i; - rta->nh.gw = IPA_NONE; - rta->nh.iface = NULL; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - break; - - case SA_IFNAME: - { - struct iface *ifa = if_find_by_name(v1.val.s); - if (!ifa) - runtime( "Invalid iface name" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = IPA_NONE; - rta->nh.iface = ifa; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - break; - - default: - bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); - } - } - } - INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */ DYNAMIC_ATTR; ACCESS_RTE; @@ -501,8 +424,7 @@ } /* Undefined value */ - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; } @@ -535,8 +457,7 @@ RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; default: bug("Unknown dynamic attribute type"); @@ -544,95 +465,6 @@ } } - INST(FI_EA_SET, 1, 0) { - ACCESS_RTE; - ACCESS_EATTRS; - ARG_ANY(1); - DYNAMIC_ATTR; - { - struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - - l->next = NULL; - l->flags = EALF_SORTED; - l->count = 1; - l->attrs[0].id = da.ea_code; - l->attrs[0].flags = 0; - l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; - - 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; - - case EAF_TYPE_OPAQUE: - 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" ); - int len = sizeof(ip_addr); - struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); - ad->length = len; - (* (ip_addr *) ad->data) = v1.val.ip; - l->attrs[0].u.ptr = ad; - break; - case EAF_TYPE_AS_PATH: - if (v1.type != T_PATH) - runtime( "Setting path attribute to non-path value" ); - 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); - u32 data = e ? e->u.data : 0; - - if (v1.val.i) - l->attrs[0].u.data = data | (1u << da.bit); - else - l->attrs[0].u.data = data & ~(1u << da.bit); - } - 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 type in e,S"); - } - - f_rta_cow(fs); - l->next = *fs->eattrs; - *fs->eattrs = l; - } - } - INST(FI_EA_UNSET, 0, 0) { DYNAMIC_ATTR; ACCESS_RTE; @@ -660,15 +492,6 @@ RESULT(T_INT, i, (*fs->rte)->pref); } - INST(FI_PREF_SET, 1, 0) { - ACCESS_RTE; - ARG(1,T_INT); - if (v1.val.i > 0xFFFF) - runtime( "Setting preference value out of bounds" ); - f_rte_cow(fs); - (*fs->rte)->pref = v1.val.i; - } - INST(FI_LENGTH, 1, 1) { /* Get length of */ ARG_ANY(1); switch(v1.type) { @@ -744,33 +567,6 @@ RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad)); } - INST(FI_RETURN, 1, 1) { - /* Acquire the return value */ - ARG_ANY(1); - uint retpos = fstk->vcnt; - - /* Drop every sub-block including ourselves */ - while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN)) - ; - - /* Now we are at the caller frame; if no such, try to convert to accept/reject. */ - if (!fstk->ecnt) - if (fstk->vstk[retpos].type == T_BOOL) - if (fstk->vstk[retpos].val.i) - - return F_ACCEPT; - else - return F_REJECT; - else - runtime("Can't return non-bool from non-function"); - - /* Set the value stack position, overwriting the former implicit void */ - fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1; - - /* Copy the return value */ - RESULT_VAL(fstk->vstk[retpos]); - } - INST(FI_CALL, 0, 1) { SYMBOL; diff --git a/filter/f-inst.h b/filter/f-inst.h index f0dcec64..ca685ded 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -84,7 +84,6 @@ static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_t { return (struct f_dynamic_attr) { .type = type, .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 }; } -struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); 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 */ diff --git a/filter/filter.c b/filter/filter.c index 9b61c707..98df7bd0 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -51,12 +51,6 @@ #include "filter/data.h" -/* Exception bits */ -enum f_exception { - FE_RETURN = 0x1, -}; - - struct filter_stack { /* Value stack for execution */ #define F_VAL_STACK_MAX 4096 @@ -151,7 +145,7 @@ f_rta_cow(struct filter_state *fs) } static char * -val_format_str(struct filter_state *fs, struct f_val *v) { +val_format_str(struct filter_state *fs, const struct f_val *v) { buffer b; LOG_BUFFER_INIT(b); val_format(v, &b); @@ -160,6 +154,233 @@ val_format_str(struct filter_state *fs, struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; +#define runtime(fmt, ...) do { \ + if (!(fs->flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, \ + (fs->stack->estk[fs->stack->ecnt-1].line->items[fs->stack->estk[fs->stack->ecnt-1].pos-1]).lineno, \ + ##__VA_ARGS__); \ + return F_ERROR; \ +} while(0) + +#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) +#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) + +static inline enum filter_return +f_rta_set(struct filter_state *fs, struct f_static_attr sa, const struct f_val *val) +{ + ACCESS_RTE; + if (sa.f_type != val->type) + runtime( "Attempt to set static attribute to incompatible type" ); + + f_rta_cow(fs); + { + struct rta *rta = (*fs->rte)->attrs; + + switch (sa.sa_code) + { + case SA_FROM: + rta->from = val->val.ip; + return F_NOP; + + case SA_GW: + { + ip_addr ip = val->val.ip; + neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = ip; + rta->nh.iface = n->iface; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + return F_NOP; + + case SA_SCOPE: + rta->scope = val->val.i; + return F_NOP; + + case SA_DEST: + { + int i = val->val.i; + if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) + runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + + rta->dest = i; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + return F_NOP; + + case SA_IFNAME: + { + struct iface *ifa = if_find_by_name(val->val.s); + if (!ifa) + runtime( "Invalid iface name" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = IPA_NONE; + rta->nh.iface = ifa; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + return F_NOP; + + default: + bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); + } + } +} + +static inline enum filter_return +f_ea_set(struct filter_state *fs, struct f_dynamic_attr da, const struct f_val *val) +{ + ACCESS_RTE; + ACCESS_EATTRS; + { + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + + l->next = NULL; + l->flags = EALF_SORTED; + l->count = 1; + l->attrs[0].id = da.ea_code; + l->attrs[0].flags = 0; + l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; + + switch (da.type) { + case EAF_TYPE_INT: + if (val->type != da.f_type) + runtime( "Setting int attribute to non-int value" ); + l->attrs[0].u.data = val->val.i; + break; + + case EAF_TYPE_ROUTER_ID: + /* IP->Quad implicit conversion */ + if (val_is_ip4(val)) { + l->attrs[0].u.data = ipa_to_u32(val->val.ip); + break; + } + /* T_INT for backward compatibility */ + if ((val->type != T_QUAD) && (val->type != T_INT)) + runtime( "Setting quad attribute to non-quad value" ); + l->attrs[0].u.data = val->val.i; + break; + + case EAF_TYPE_OPAQUE: + runtime( "Setting opaque attribute is not allowed" ); + break; + case EAF_TYPE_IP_ADDRESS: + if (val->type != T_IP) + runtime( "Setting ip attribute to non-ip value" ); + int len = sizeof(ip_addr); + struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); + ad->length = len; + (* (ip_addr *) ad->data) = val->val.ip; + l->attrs[0].u.ptr = ad; + break; + case EAF_TYPE_AS_PATH: + if (val->type != T_PATH) + runtime( "Setting path attribute to non-path value" ); + l->attrs[0].u.ptr = val->val.ad; + break; + case EAF_TYPE_BITFIELD: + if (val->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); + u32 data = e ? e->u.data : 0; + + if (val->val.i) + l->attrs[0].u.data = data | (1u << da.bit); + else + l->attrs[0].u.data = data & ~(1u << da.bit); + } + break; + case EAF_TYPE_INT_SET: + if (val->type != T_CLIST) + runtime( "Setting clist attribute to non-clist value" ); + l->attrs[0].u.ptr = val->val.ad; + break; + case EAF_TYPE_EC_SET: + if (val->type != T_ECLIST) + runtime( "Setting eclist attribute to non-eclist value" ); + l->attrs[0].u.ptr = val->val.ad; + break; + case EAF_TYPE_LC_SET: + if (val->type != T_LCLIST) + runtime( "Setting lclist attribute to non-lclist value" ); + l->attrs[0].u.ptr = val->val.ad; + break; + default: bug("Unknown type in e,S"); + } + + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; + + return F_NOP; + } +} + +static inline enum filter_return +f_lval_set(struct filter_state *fs, const struct f_lval *lv, const struct f_val *val) +{ + switch (lv->type) { + case F_LVAL_STACK: + fs->stack->vstk[fs->stack->vcnt] = *val; + fs->stack->vcnt++; + return F_NOP; + case F_LVAL_EXCEPTION: + { + /* Drop every sub-block including ourselves */ + while ((fs->stack->ecnt-- > 0) && !(fs->stack->estk[fs->stack->ecnt].emask & lv->exception)) + ; + + /* Now we are at the catch frame; if no such, try to convert to accept/reject. */ + if (!fs->stack->ecnt) + if (lv->exception == FE_RETURN) + if (val->type == T_BOOL) + if (val->val.i) + return F_ACCEPT; + else + return F_REJECT; + else + runtime("Can't return non-bool from non-function"); + else + runtime("Unhandled exception 0x%x: %s", lv->exception, val_format_str(fs, val)); + + /* Set the value stack position, overwriting the former implicit void */ + fs->stack->vcnt = fs->stack->estk[fs->stack->ecnt].ventry; + + /* Copy the return value */ + fs->stack->vstk[fs->stack->vcnt - 1] = *val; + return F_NOP; + } + case F_LVAL_VARIABLE: + fs->stack->vstk[fs->stack->estk[fs->stack->ecnt-1].vbase + lv->sym->offset] = *val; + return F_NOP; + case F_LVAL_PREFERENCE: + ACCESS_RTE; + if (val->type != T_INT) + runtime("Preference must be integer, got 0x%02x", val->type); + if (val->val.i > 0xFFFF) + runtime("Preference is at most 65536"); + f_rte_cow(fs); + (*fs->rte)->pref = val->val.i; + return F_NOP; + case F_LVAL_SA: + return f_rta_set(fs, lv->sa, val); + case F_LVAL_EA: + return f_ea_set(fs, lv->da, val); + default: + bug("This shall never happen"); + } +} + /** * interpret * @fs: filter state @@ -209,15 +430,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define v2 fstk->vstk[fstk->vcnt + 1] #define v3 fstk->vstk[fstk->vcnt + 2] -#define runtime(fmt, ...) do { \ - if (!(fs->flags & FF_SILENT)) \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ - return F_ERROR; \ -} while(0) - -#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) -#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) - #include "filter/inst-interpret.c" #undef res #undef v1 @@ -233,6 +445,16 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) fstk->vcnt -= curline.line->vars; fstk->vcnt -= curline.line->args; fstk->ecnt--; + + /* If the caller wants to store the result somewhere, do it. */ + if (fstk->ecnt) { + const struct f_line_item *caller = &(curline.line->items[curline.pos-1]); + if (caller->result.type != F_LVAL_STACK) { + enum filter_return fret = f_lval_set(fs, &(caller->result), &fstk->vstk[--fstk->vcnt]); + if (fret != F_NOP) + return fret; + } + } } if (fstk->vcnt == 0) { From 87c82334a77dfa3fea3057fa6d4bcf8558f203a4 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 13 Jun 2019 14:24:48 +0200 Subject: [PATCH 59/88] Filter: removal of semantically insane consts in filter_commit --- filter/filter.c | 2 +- filter/filter.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 98df7bd0..77378178 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -680,7 +680,7 @@ filter_same(const struct filter *new, const struct filter *old) * filter_commit - do filter comparisons on all the named functions and filters */ void -filter_commit(const struct config *new, const struct config *old) +filter_commit(struct config *new, struct config *old) { if (!old) return; diff --git a/filter/filter.h b/filter/filter.h index d919cc74..36b63e7c 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -62,7 +62,7 @@ const char *filter_name(const struct filter *filter); int filter_same(const struct filter *new, const struct filter *old); int f_same(const struct f_line *f1, const struct f_line *f2); -void filter_commit(const struct config *new, const struct config *old); +void filter_commit(struct config *new, struct config *old); #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) From 5c864e2cfaf5ff5e8e3db3ccd746162fbc7aac5b Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 13 Jun 2019 14:27:58 +0200 Subject: [PATCH 60/88] String: bstrtoul macro expanded to bstrtoul10 and 16 --- conf/cf-lex.l | 14 +++++++------- lib/ip.c | 2 +- lib/string.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 83e4e77c..09f3db8d 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -168,7 +168,7 @@ WHITE [ \t] char *e; errno = 0; - l = bstrtoul(yytext, &e, 10); + l = bstrtoul10(yytext, &e); if (e && (*e != ':') || (errno == ERANGE) || (l >> 32)) cf_error("ASN out of range"); @@ -186,7 +186,7 @@ WHITE [ \t] } errno = 0; - l = bstrtoul(e+1, &e, 10); + l = bstrtoul10(e+1, &e); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -213,13 +213,13 @@ WHITE [ \t] } errno = 0; - l = bstrtoul(yytext+2, &e, 10); + l = bstrtoul10(yytext+2, &e); if (e && (*e != ':') || (errno == ERANGE) || (l >> len1)) cf_error("ASN out of range"); cf_lval.i64 |= ((u64) l) << len2; errno = 0; - l = bstrtoul(e+1, &e, 10); + l = bstrtoul10(e+1, &e); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -241,7 +241,7 @@ WHITE [ \t] cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16; errno = 0; - l = bstrtoul(e, &e, 10); + l = bstrtoul10(e, &e); if (e && *e || (errno == ERANGE) || (l >> 16)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -265,7 +265,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = bstrtoul(yytext+2, &e, 16); + l = bstrtoul16(yytext+2, &e); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; @@ -276,7 +276,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = bstrtoul(yytext, &e, 10); + l = bstrtoul10(yytext, &e); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; diff --git a/lib/ip.c b/lib/ip.c index 0f5a5348..2d195160 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -245,7 +245,7 @@ ip4_pton(const char *a, ip4_addr *o) char *d, *c = strchr(a, '.'); if (!c != !i) return 0; - l = bstrtoul(a, &d, 10); + l = bstrtoul10(a, &d); if (((d != c) && *d) || (l > 255)) return 0; ia = (ia << 8) | l; diff --git a/lib/string.h b/lib/string.h index 5f7c4666..6e549cb7 100644 --- a/lib/string.h +++ b/lib/string.h @@ -24,7 +24,6 @@ int buffer_vprint(buffer *buf, const char *fmt, va_list args); int buffer_print(buffer *buf, const char *fmt, ...); void buffer_puts(buffer *buf, const char *str); -#define bstrtoul(str, end, base) bstrtoul##base(str, end) u64 bstrtoul10(const char *str, char **end); u64 bstrtoul16(const char *str, char **end); From a84b8b6ebb2b6825b7059e34cfaafe405ab0117e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 19 Jun 2019 14:09:57 +0200 Subject: [PATCH 61/88] Revert "Filter: Dropped the setter instructions in favor of direct result storage." This reverts commit bd91338246c1ba40358243f1bdf5a6dbd3a29f35. --- filter/config.Y | 59 ++++------- filter/data.c | 1 + filter/data.h | 8 -- filter/decl.m4 | 69 +------------ filter/f-inst.c | 232 ++++++++++++++++++++++++++++++++++++++++--- filter/f-inst.h | 1 + filter/filter.c | 254 +++--------------------------------------------- 7 files changed, 260 insertions(+), 364 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index f57575fc..3898748c 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -21,13 +21,9 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } -#define f_generate_complex(fi_code, _da, arg) ({ \ - struct f_inst *fi = f_new_inst(fi_code, f_new_inst(FI_EA_GET, _da), arg); \ - fi->result.type = F_LVAL_EA; \ - fi->result.da = _da; \ - fi; \ -}) - +#define f_generate_complex(fi_code, da, arg) \ + f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) + /* * Sets and their items are during parsing handled as lists, linked * through left ptr. The first item in a list also contains a pointer @@ -188,10 +184,7 @@ f_generate_empty(struct f_dynamic_attr dyn) cf_error("Can't empty that attribute"); } - struct f_inst *fi = f_new_inst(FI_CONSTANT, empty); - fi->result.type = F_LVAL_EA; - fi->result.da = dyn; - return fi; + return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); } #if 0 @@ -404,34 +397,31 @@ assert_done(struct f_inst *expr, const char *start, const char *end) static struct f_inst * assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end) { - struct f_inst *getter; + struct f_inst *setter, *getter, *checker; switch (lval->type) { - case F_LVAL_STACK: - bug("This shall never happen"); - case F_LVAL_EXCEPTION: - bug("This shall never happen"); case F_LVAL_VARIABLE: + setter = f_new_inst(FI_VAR_SET, expr, lval->sym); getter = f_new_inst(FI_VAR_GET, lval->sym); break; case F_LVAL_PREFERENCE: + setter = f_new_inst(FI_PREF_SET, expr); getter = f_new_inst(FI_PREF_GET); break; case F_LVAL_SA: + setter = f_new_inst(FI_RTA_SET, expr, lval->sa); getter = f_new_inst(FI_RTA_GET, lval->sa); break; case F_LVAL_EA: + setter = f_new_inst(FI_EA_SET, expr, lval->da); getter = f_new_inst(FI_EA_GET, lval->da); break; + default: + bug("Unknown lval type"); } - struct f_inst *checker = f_new_inst(FI_EQ, expr, getter); - - struct f_inst *setter = cfg_alloc(sizeof(struct f_inst)); - *setter = *expr; - + checker = f_new_inst(FI_EQ, expr, getter); setter->next = checker; - setter->result = *lval; - + return assert_done(setter, start, end); } @@ -995,40 +985,29 @@ cmd: | CF_SYM_KNOWN '=' term ';' { switch ($1->class) { case SYM_VARIABLE_RANGE: - $3->result.type = F_LVAL_VARIABLE; - $3->result.sym = $1; + $$ = f_new_inst(FI_VAR_SET, $3, $1); break; case SYM_ATTRIBUTE: - $3->result.type = F_LVAL_EA; - $3->result.da = *$1->attribute; + $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); break; default: cf_error("Can't assign to symbol %s", $1->name); } - $$ = $3; } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); - $2->result.type = F_LVAL_EXCEPTION; - $2->result.exception = FE_RETURN; - $$ = $2; + $$ = f_new_inst(FI_RETURN, $2); } | dynamic_attr '=' term ';' { - $3->result.type = F_LVAL_EA; - $3->result.da = $1; - $$ = $3; + $$ = f_new_inst(FI_EA_SET, $3, $1); } | static_attr '=' term ';' { if ($1.readonly) cf_error( "This static attribute is read-only."); - - $3->result.type = F_LVAL_SA; - $3->result.sa = $1; - $$ = $3; + $$ = f_new_inst(FI_RTA_SET, $3, $1); } | PREFERENCE '=' term ';' { - $3->result.type = F_LVAL_PREFERENCE; - $$ = $3; + $$ = f_new_inst(FI_PREF_SET, $3); } | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); diff --git a/filter/data.c b/filter/data.c index cb759a59..912e2b00 100644 --- a/filter/data.c +++ b/filter/data.c @@ -525,3 +525,4 @@ val_dump(const struct f_val *v) { val_format(v, &b); return val_dump_buffer; } + diff --git a/filter/data.h b/filter/data.h index 3718cea4..6973008f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -107,15 +107,8 @@ struct f_static_attr { int readonly:1; /* Don't allow writing */ }; -/* Exception bits */ -enum f_exception { - FE_RETURN = 0x1, -}; - /* Filter l-value type */ enum f_lval_type { - F_LVAL_STACK = 0, - F_LVAL_EXCEPTION, F_LVAL_VARIABLE, F_LVAL_PREFERENCE, F_LVAL_SA, @@ -126,7 +119,6 @@ enum f_lval_type { struct f_lval { enum f_lval_type type; union { - enum f_exception exception; const struct symbol *sym; struct f_dynamic_attr da; struct f_static_attr sa; diff --git a/filter/decl.m4 b/filter/decl.m4 index a1d625f3..9934d0ba 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -119,6 +119,8 @@ case INST_NAME(): { m4_undivert(105) #undef what #undef item + dest->items[pos].fi_code = what_->fi_code; + dest->items[pos].lineno = what_->lineno; break; } m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) @@ -234,29 +236,9 @@ do { if (whati->fl$1) { } } while(0)m4_dnl FID_ALL()') -m4_define(RESULT_PTR, ` -FID_INTERPRET_BODY - do { - enum filter_return fret = f_lval_set(fs, &(what->result), $1); - if (fret != F_NOP) return fret; - } while (0)m4_dnl -FID_ALL()') - -m4_define(RESULT, ` -FID_INTERPRET_BODY - do { - struct f_val res_ = { .type = $1, .val.$2 = $3 }; - RESULT_PTR(&res_); - } while (0)m4_dnl -FID_ALL()') - -m4_define(RESULT_VOID, ` -FID_INTERPRET_BODY - do { - struct f_val res_ = { .type = T_VOID }; - RESULT_PTR(&res_); - } while (0)m4_dnl -FID_ALL()') +m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()') +m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') +m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') @@ -320,16 +302,6 @@ void f_dump_line(const struct f_line *dest, uint indent) for (uint i=0; ilen; i++) { const struct f_line_item *item = &dest->items[i]; debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); - - switch (item->result.type) { - case F_LVAL_STACK: debug("%son stack\n", INDENT); break; - case F_LVAL_EXCEPTION: debug("%s=>exception 0x%x\n", INDENT, item->result.exception); break; - case F_LVAL_VARIABLE: debug("%s=>%s\n", INDENT, item->result.sym->name); break; - case F_LVAL_PREFERENCE: debug("%s=>preference\n", INDENT); break; - case F_LVAL_SA: debug("%s=>sa\n", INDENT); break; - case F_LVAL_EA: debug("%s=>ea\n", INDENT); break; - } - switch (item->fi_code) { FID_WR_PUT(7) default: bug("Unknown instruction %x in f_dump_line", item->fi_code); @@ -346,9 +318,6 @@ linearize(struct f_line *dest, const struct f_inst *what_, uint pos) switch (what_->fi_code) { FID_WR_PUT(8) } - dest->items[pos].fi_code = what_->fi_code; - dest->items[pos].lineno = what_->lineno; - dest->items[pos].result = what_->result; pos++; } return pos; @@ -391,32 +360,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2) if (f1_->flags != f2_->flags) return 0; - if (f1_->result.type != f2_->result.type) return 0; - switch (f1_->result.type) { - case F_LVAL_STACK: - break; - case F_LVAL_EXCEPTION: - if (f1_->result.exception != f2_->result.exception) - return 0; - break; - case F_LVAL_VARIABLE: - if (strcmp(f1_->result.sym->name, f2_->result.sym->name)) - return 0; - if (f1_->result.sym->class != f2_->result.sym->class) - return 0; - break; - case F_LVAL_PREFERENCE: - break; - case F_LVAL_SA: - if (f1_->result.sa.sa_code != f2_->result.sa.sa_code) - return 0; - break; - case F_LVAL_EA: - if (f1_->result.da.ea_code != f2_->result.da.ea_code) - return 0; - break; - } - switch(f1_->fi_code) { FID_WR_PUT(9) } @@ -439,7 +382,6 @@ struct f_inst { enum f_instruction_code fi_code; /* Instruction code */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ - struct f_lval result; /* Destination */ union { FID_WR_PUT(1) }; @@ -450,7 +392,6 @@ struct f_line_item { enum f_instruction_code fi_code; /* What to do */ enum f_instruction_flags flags; /* Flags, instruction-specific */ uint lineno; /* Where */ - struct f_lval result; /* Destination */ union { FID_WR_PUT(2) }; diff --git a/filter/f-inst.c b/filter/f-inst.c index 3be76d11..749e072c 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -36,7 +36,7 @@ * m4_dnl ACCESS_RTE; this instruction needs route * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes * m4_dnl RESULT(type, union-field, value); putting this on value stack - * m4_dnl RESULT_PTR(vptr); put what is pointed-to on the value stack + * m4_dnl RESULT_OK; legalize what already is on the value stack * m4_dnl } * * Other code is just copied into the interpreter part. @@ -50,37 +50,41 @@ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i + v2.val.i); + res.val.i += v2.val.i; + RESULT_OK; } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i - v2.val.i); + res.val.i -= v2.val.i; + RESULT_OK; } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i * v2.val.i); + res.val.i *= v2.val.i; + RESULT_OK; } INST(FI_DIVIDE, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); - RESULT(T_INT, i, v1.val.i / v2.val.i); + res.val.i /= v2.val.i; + RESULT_OK; } INST(FI_AND, 1, 1) { ARG(1,T_BOOL); - if (v1.val.i) + if (res.val.i) LINE(2,0); else - RESULT_PTR(&(v1)); + RESULT_OK; } INST(FI_OR, 1, 1) { ARG(1,T_BOOL); - if (!v1.val.i) + if (!res.val.i) LINE(2,0); else - RESULT_PTR(&(v1)); + RESULT_OK; } INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); @@ -277,7 +281,8 @@ INST(FI_VAR_GET, 0, 1) { SYMBOL(1); - RESULT_PTR(&(fstk->vstk[curline.vbase + sym->offset])); + res = fstk->vstk[curline.vbase + sym->offset]; + RESULT_OK; } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -298,7 +303,8 @@ debug("%svalue %s\n", INDENT, val_dump(&item->val)); FID_ALL - RESULT_PTR(&(whati->val)); + res = whati->val; + RESULT_OK; } INST(FI_CONSTANT_DEFINED, 0, 1) { FID_STRUCT_IN @@ -318,7 +324,8 @@ debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); FID_ALL - RESULT_PTR(whati->valp); + res = *whati->valp; + RESULT_OK; } INST(FI_PRINT, 1, 0) { ARG_ANY(1); @@ -391,6 +398,76 @@ } } + INST(FI_RTA_SET, 1, 0) { + ACCESS_RTE; + ARG_ANY(1); + STATIC_ATTR; + if (sa.f_type != v1.type) + runtime( "Attempt to set static attribute to incompatible type" ); + + f_rta_cow(fs); + { + struct rta *rta = (*fs->rte)->attrs; + + switch (sa.sa_code) + { + case SA_FROM: + rta->from = v1.val.ip; + break; + + case SA_GW: + { + ip_addr ip = v1.val.ip; + neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = ip; + rta->nh.iface = n->iface; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + case SA_SCOPE: + rta->scope = v1.val.i; + break; + + case SA_DEST: + { + int i = v1.val.i; + if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) + runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + + rta->dest = i; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + case SA_IFNAME: + { + struct iface *ifa = if_find_by_name(v1.val.s); + if (!ifa) + runtime( "Invalid iface name" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = IPA_NONE; + rta->nh.iface = ifa; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + default: + bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); + } + } + } + INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */ DYNAMIC_ATTR; ACCESS_RTE; @@ -424,7 +501,8 @@ } /* Undefined value */ - RESULT_VOID; + res.type = T_VOID; + RESULT_OK; break; } @@ -457,7 +535,8 @@ RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: - RESULT_VOID; + res.type = T_VOID; + RESULT_OK; break; default: bug("Unknown dynamic attribute type"); @@ -465,6 +544,95 @@ } } + INST(FI_EA_SET, 1, 0) { + ACCESS_RTE; + ACCESS_EATTRS; + ARG_ANY(1); + DYNAMIC_ATTR; + { + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + + l->next = NULL; + l->flags = EALF_SORTED; + l->count = 1; + l->attrs[0].id = da.ea_code; + l->attrs[0].flags = 0; + l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; + + 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; + + case EAF_TYPE_OPAQUE: + 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" ); + int len = sizeof(ip_addr); + struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); + ad->length = len; + (* (ip_addr *) ad->data) = v1.val.ip; + l->attrs[0].u.ptr = ad; + break; + case EAF_TYPE_AS_PATH: + if (v1.type != T_PATH) + runtime( "Setting path attribute to non-path value" ); + 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); + u32 data = e ? e->u.data : 0; + + if (v1.val.i) + l->attrs[0].u.data = data | (1u << da.bit); + else + l->attrs[0].u.data = data & ~(1u << da.bit); + } + 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 type in e,S"); + } + + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; + } + } + INST(FI_EA_UNSET, 0, 0) { DYNAMIC_ATTR; ACCESS_RTE; @@ -492,6 +660,15 @@ RESULT(T_INT, i, (*fs->rte)->pref); } + INST(FI_PREF_SET, 1, 0) { + ACCESS_RTE; + ARG(1,T_INT); + if (v1.val.i > 0xFFFF) + runtime( "Setting preference value out of bounds" ); + f_rte_cow(fs); + (*fs->rte)->pref = v1.val.i; + } + INST(FI_LENGTH, 1, 1) { /* Get length of */ ARG_ANY(1); switch(v1.type) { @@ -567,6 +744,33 @@ RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad)); } + INST(FI_RETURN, 1, 1) { + /* Acquire the return value */ + ARG_ANY(1); + uint retpos = fstk->vcnt; + + /* Drop every sub-block including ourselves */ + while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN)) + ; + + /* Now we are at the caller frame; if no such, try to convert to accept/reject. */ + if (!fstk->ecnt) + if (fstk->vstk[retpos].type == T_BOOL) + if (fstk->vstk[retpos].val.i) + + return F_ACCEPT; + else + return F_REJECT; + else + runtime("Can't return non-bool from non-function"); + + /* Set the value stack position, overwriting the former implicit void */ + fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1; + + /* Copy the return value */ + RESULT_VAL(fstk->vstk[retpos]); + } + INST(FI_CALL, 0, 1) { SYMBOL; diff --git a/filter/f-inst.h b/filter/f-inst.h index ca685ded..f0dcec64 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -84,6 +84,7 @@ static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_t { return (struct f_dynamic_attr) { .type = type, .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 }; } +struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); 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 */ diff --git a/filter/filter.c b/filter/filter.c index 77378178..ee29522e 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -51,6 +51,12 @@ #include "filter/data.h" +/* Exception bits */ +enum f_exception { + FE_RETURN = 0x1, +}; + + struct filter_stack { /* Value stack for execution */ #define F_VAL_STACK_MAX 4096 @@ -145,7 +151,7 @@ f_rta_cow(struct filter_state *fs) } static char * -val_format_str(struct filter_state *fs, const struct f_val *v) { +val_format_str(struct filter_state *fs, struct f_val *v) { buffer b; LOG_BUFFER_INIT(b); val_format(v, &b); @@ -154,233 +160,6 @@ val_format_str(struct filter_state *fs, const struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -#define runtime(fmt, ...) do { \ - if (!(fs->flags & FF_SILENT)) \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, \ - (fs->stack->estk[fs->stack->ecnt-1].line->items[fs->stack->estk[fs->stack->ecnt-1].pos-1]).lineno, \ - ##__VA_ARGS__); \ - return F_ERROR; \ -} while(0) - -#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) -#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) - -static inline enum filter_return -f_rta_set(struct filter_state *fs, struct f_static_attr sa, const struct f_val *val) -{ - ACCESS_RTE; - if (sa.f_type != val->type) - runtime( "Attempt to set static attribute to incompatible type" ); - - f_rta_cow(fs); - { - struct rta *rta = (*fs->rte)->attrs; - - switch (sa.sa_code) - { - case SA_FROM: - rta->from = val->val.ip; - return F_NOP; - - case SA_GW: - { - ip_addr ip = val->val.ip; - neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); - if (!n || (n->scope == SCOPE_HOST)) - runtime( "Invalid gw address" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = ip; - rta->nh.iface = n->iface; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - case SA_SCOPE: - rta->scope = val->val.i; - return F_NOP; - - case SA_DEST: - { - int i = val->val.i; - if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) - runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); - - rta->dest = i; - rta->nh.gw = IPA_NONE; - rta->nh.iface = NULL; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - case SA_IFNAME: - { - struct iface *ifa = if_find_by_name(val->val.s); - if (!ifa) - runtime( "Invalid iface name" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = IPA_NONE; - rta->nh.iface = ifa; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - default: - bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); - } - } -} - -static inline enum filter_return -f_ea_set(struct filter_state *fs, struct f_dynamic_attr da, const struct f_val *val) -{ - ACCESS_RTE; - ACCESS_EATTRS; - { - struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - - l->next = NULL; - l->flags = EALF_SORTED; - l->count = 1; - l->attrs[0].id = da.ea_code; - l->attrs[0].flags = 0; - l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; - - switch (da.type) { - case EAF_TYPE_INT: - if (val->type != da.f_type) - runtime( "Setting int attribute to non-int value" ); - l->attrs[0].u.data = val->val.i; - break; - - case EAF_TYPE_ROUTER_ID: - /* IP->Quad implicit conversion */ - if (val_is_ip4(val)) { - l->attrs[0].u.data = ipa_to_u32(val->val.ip); - break; - } - /* T_INT for backward compatibility */ - if ((val->type != T_QUAD) && (val->type != T_INT)) - runtime( "Setting quad attribute to non-quad value" ); - l->attrs[0].u.data = val->val.i; - break; - - case EAF_TYPE_OPAQUE: - runtime( "Setting opaque attribute is not allowed" ); - break; - case EAF_TYPE_IP_ADDRESS: - if (val->type != T_IP) - runtime( "Setting ip attribute to non-ip value" ); - int len = sizeof(ip_addr); - struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); - ad->length = len; - (* (ip_addr *) ad->data) = val->val.ip; - l->attrs[0].u.ptr = ad; - break; - case EAF_TYPE_AS_PATH: - if (val->type != T_PATH) - runtime( "Setting path attribute to non-path value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_BITFIELD: - if (val->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); - u32 data = e ? e->u.data : 0; - - if (val->val.i) - l->attrs[0].u.data = data | (1u << da.bit); - else - l->attrs[0].u.data = data & ~(1u << da.bit); - } - break; - case EAF_TYPE_INT_SET: - if (val->type != T_CLIST) - runtime( "Setting clist attribute to non-clist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_EC_SET: - if (val->type != T_ECLIST) - runtime( "Setting eclist attribute to non-eclist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_LC_SET: - if (val->type != T_LCLIST) - runtime( "Setting lclist attribute to non-lclist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - default: bug("Unknown type in e,S"); - } - - f_rta_cow(fs); - l->next = *fs->eattrs; - *fs->eattrs = l; - - return F_NOP; - } -} - -static inline enum filter_return -f_lval_set(struct filter_state *fs, const struct f_lval *lv, const struct f_val *val) -{ - switch (lv->type) { - case F_LVAL_STACK: - fs->stack->vstk[fs->stack->vcnt] = *val; - fs->stack->vcnt++; - return F_NOP; - case F_LVAL_EXCEPTION: - { - /* Drop every sub-block including ourselves */ - while ((fs->stack->ecnt-- > 0) && !(fs->stack->estk[fs->stack->ecnt].emask & lv->exception)) - ; - - /* Now we are at the catch frame; if no such, try to convert to accept/reject. */ - if (!fs->stack->ecnt) - if (lv->exception == FE_RETURN) - if (val->type == T_BOOL) - if (val->val.i) - return F_ACCEPT; - else - return F_REJECT; - else - runtime("Can't return non-bool from non-function"); - else - runtime("Unhandled exception 0x%x: %s", lv->exception, val_format_str(fs, val)); - - /* Set the value stack position, overwriting the former implicit void */ - fs->stack->vcnt = fs->stack->estk[fs->stack->ecnt].ventry; - - /* Copy the return value */ - fs->stack->vstk[fs->stack->vcnt - 1] = *val; - return F_NOP; - } - case F_LVAL_VARIABLE: - fs->stack->vstk[fs->stack->estk[fs->stack->ecnt-1].vbase + lv->sym->offset] = *val; - return F_NOP; - case F_LVAL_PREFERENCE: - ACCESS_RTE; - if (val->type != T_INT) - runtime("Preference must be integer, got 0x%02x", val->type); - if (val->val.i > 0xFFFF) - runtime("Preference is at most 65536"); - f_rte_cow(fs); - (*fs->rte)->pref = val->val.i; - return F_NOP; - case F_LVAL_SA: - return f_rta_set(fs, lv->sa, val); - case F_LVAL_EA: - return f_ea_set(fs, lv->da, val); - default: - bug("This shall never happen"); - } -} - /** * interpret * @fs: filter state @@ -430,6 +209,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define v2 fstk->vstk[fstk->vcnt + 1] #define v3 fstk->vstk[fstk->vcnt + 2] +#define runtime(fmt, ...) do { \ + if (!(fs->flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + return F_ERROR; \ +} while(0) + +#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) +#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) + #include "filter/inst-interpret.c" #undef res #undef v1 @@ -445,16 +233,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) fstk->vcnt -= curline.line->vars; fstk->vcnt -= curline.line->args; fstk->ecnt--; - - /* If the caller wants to store the result somewhere, do it. */ - if (fstk->ecnt) { - const struct f_line_item *caller = &(curline.line->items[curline.pos-1]); - if (caller->result.type != F_LVAL_STACK) { - enum filter_return fret = f_lval_set(fs, &(caller->result), &fstk->vstk[--fstk->vcnt]); - if (fret != F_NOP) - return fret; - } - } } if (fstk->vcnt == 0) { From 2e0777317f373921487d80e88c376d23a842ba2c Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 21 Jun 2019 11:33:28 +0200 Subject: [PATCH 62/88] Filter instructions don't confuse now v1 and res. --- filter/f-inst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 749e072c..7349bf72 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -50,26 +50,26 @@ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i += v2.val.i; + res.val.i = v1.val.i + v2.val.i; RESULT_OK; } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i -= v2.val.i; + res.val.i = v1.val.i - v2.val.i; RESULT_OK; } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i *= v2.val.i; + res.val.i = v1.val.i * v2.val.i; RESULT_OK; } INST(FI_DIVIDE, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); - res.val.i /= v2.val.i; + res.val.i = v1.val.i / v2.val.i; RESULT_OK; } INST(FI_AND, 1, 1) { From 63e7620462b80c9c6bbbd4f128b6816e0748d6c6 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 25 Jun 2019 16:18:06 +0200 Subject: [PATCH 63/88] Conf/Filters: Moved argument count to conf scope --- conf/cf-lex.l | 1 + conf/conf.h | 1 + filter/config.Y | 23 +++++++++++------------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 09f3db8d..0aa9273f 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -742,6 +742,7 @@ cf_push_scope(struct symbol *sym) conf_this_scope = s; s->active = 1; s->name = sym; + s->slots = 0; } /** diff --git a/conf/conf.h b/conf/conf.h index d88d9a44..708a1034 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -126,6 +126,7 @@ struct symbol { struct sym_scope { struct sym_scope *next; /* Next on scope stack */ struct symbol *name; /* Name of this scope */ + uint slots; /* Variable slots */ int active; /* Currently entered */ }; diff --git a/filter/config.Y b/filter/config.Y index 3898748c..72866bb0 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -15,8 +15,6 @@ CF_HDR CF_DEFINES -static uint decls_count; - static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; } @@ -455,7 +453,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type filter where_filter %type filter_body function_body %type lvalue -%type type function_params +%type type function_params declsn decls %type ec_kind %type break_command %type cnum @@ -557,22 +555,24 @@ type: /* Declarations with ';' at the end */ decls: - /* EMPTY */ - | declsn ';' + /* EMPTY */ { $$ = 0; } + | declsn ';' { $$ = $1; } ; /* Declarations that have no ';' at the end. */ declsn: type CF_SYM_VOID { - cf_define_symbol($2, SYM_VARIABLE | $1, offset, decls_count++); + cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++); + $$ = $2->scope->slots; } | declsn ';' type CF_SYM_VOID { - if (decls_count >= 0xff) cf_error("Too many declarations, at most 255 allowed"); - cf_define_symbol($4, SYM_VARIABLE | $3, offset, decls_count++); + if ($4->scope->slots >= 0xff) cf_error("Too many declarations, at most 255 allowed"); + cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++); + $$ = $4->scope->slots; } ; -filter_body: { decls_count = 0; } function_body { $$ = $2; } ; +filter_body: function_body ; filter: CF_SYM_KNOWN { @@ -594,14 +594,14 @@ where_filter: ; function_params: - '(' declsn ')' { $$ = decls_count; } + '(' declsn ')' { $$ = $2; } | '(' ')' { $$ = 0; } ; function_body: decls '{' cmds '}' { $$ = f_linearize($3); - $$->vars = decls_count; + $$->vars = $1; } ; @@ -610,7 +610,6 @@ function_def: FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope($2); - decls_count = 0; } function_params function_body { $5->vars -= $4; $5->args = $4; From 64bb1346c71cbd2764b1e0a00dc88290bec72a5a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 27 Jun 2019 15:55:48 +0200 Subject: [PATCH 64/88] Filter: A little cleanup of M4 interpreter generator --- filter/decl.m4 | 60 ++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 9934d0ba..88808973 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -28,9 +28,8 @@ m4_divert(-1)m4_dnl # 107 struct f_line_item content # 108 interpreter body # -# Diversions for TARGET=I: 7xx -# Diversions for TARGET=C: 8xx -# Diversions for TARGET=H: 9xx +# Final diversions +# 200+ completed text before it is flushed to output # Flush the completed instruction m4_define(FID_END, `m4_divert(-1)') @@ -61,10 +60,7 @@ m4_define(FID_INTERPRET_BODY, `m4_divert(108)') m4_define(FID_ALL, `FID_INTERPRET_BODY'); m4_define(FID_ALL_TARGETS, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') -m4_define(FID_C, `m4_ifelse(TARGET, [[C]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') -m4_define(FID_I, `m4_ifelse(TARGET, [[I]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') -m4_define(FID_H, `m4_ifelse(TARGET, [[H]], FID_ALL_TARGETS, [[m4_define(FID_CURDIV, m4_divnum)m4_divert(-1)]])') - +m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], $1, TARGET, [[I]], $2, TARGET, [[C]], $3)') m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ FID_ENUM @@ -83,19 +79,21 @@ FID_NEW struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code m4_undivert(102) ) -FID_H -; -FID_C -{ - struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); - what_->fi_code = fi_code; - what_->lineno = ifs->lino; - what_->size = 1; -#define what (&(what_->i_]]INST_NAME()[[)) -m4_undivert(103) -#undef what - return what_; -} +FID_HIC( +[[;]], +[[]], +[[ + { + struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); + what_->fi_code = fi_code; + what_->lineno = ifs->lino; + what_->size = 1; + #define what (&(what_->i_]]INST_NAME()[[)) + [[m4_undivert(103)]] + #undef what + return what_; + } +]]) FID_DUMP_CALLER case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; @@ -110,7 +108,6 @@ m4_undefine([[FID_DUMP_BODY_EXISTS]]) m4_undivert(104) #undef item } -FID_ALL_TARGETS FID_LINEARIZE case INST_NAME(): { @@ -253,18 +250,16 @@ m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1-> m4_define(STRING, `FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s)') m4_define(FID_WR_PUT_LIST) -m4_define(FID_WR_DROP_LIST) +m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)') -m4_define(FID_WR_IPUT, `m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1))m4_define([[FID_WR_PUT_LIST]], FID_WR_PUT_LIST[[]]FID_WR_DPUT($1)FID_WR_DPUT(FID_WR_CUR_DIRECT))m4_divert(FID_WR_CUR_DIRECT)') -m4_define(FID_WR_IDROP, `m4_define([[FID_WR_CUR_DIRECT]], m4_eval(FID_WR_CUR_DIRECT + 1))m4_define([[FID_WR_DROP_LIST]], FID_WR_DROP_LIST[[]]FID_WR_DPUT($1)FID_WR_DPUT(FID_WR_CUR_DIRECT))m4_divert(FID_WR_CUR_DIRECT)') +m4_define(FID_WR_DIRECT, `m4_ifelse(TARGET,[[$1]],[[FID_WR_INIT()]],[[FID_WR_STOP()]])') +m4_define(FID_WR_INIT, `m4_define([[FID_WR_DIDX]],200)m4_define([[FID_WR_PUT]],[[FID_WR_PUT_ALSO($]][[@)]])m4_divert(200)') +m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)') -m4_define(FID_WR_DIRECT, `m4_define([[FID_WR_CUR_DIRECT]],$1)m4_ifelse(TARGET,[[$2]],[[m4_define([[FID_WR_PUT]], [[FID_WR_IPUT($]][[@)]])m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST[[]]FID_WR_DPUT($1))]],[[m4_define([[FID_WR_PUT]], [[FID_WR_IDROP($]][[@)]])m4_define([[FID_WR_DROP_LIST]],FID_WR_DROP_LIST[[]]FID_WR_DPUT($1))]])m4_divert($1)') - -m4_dnl m4_define(FID_WR_CUR_DIRECT,m4_ifelse(TARGET,`C',800,TARGET,`H',900,m4_errprint(`Bad TARGET: 'TARGET)m4_m4exit(1))) m4_changequote([[,]]) -FID_WR_DIRECT(700,I) +FID_WR_DIRECT(I) FID_WR_PUT(10) -FID_WR_DIRECT(800,C) +FID_WR_DIRECT(C) #include "nest/bird.h" #include "filter/filter.h" #include "filter/f-inst.h" @@ -370,7 +365,7 @@ FID_WR_PUT(9) } -FID_WR_DIRECT(900,H) +FID_WR_DIRECT(H) /* Filter instruction codes */ enum f_instruction_code { FID_WR_PUT(4) @@ -403,6 +398,9 @@ FID_WR_PUT(3) m4_divert(-1) m4_changequote(`,') -m4_m4wrap(`INST_FLUSH()m4_define(FID_WR_DPUT, [[m4_undivert($1)]])m4_divert(0)FID_WR_PUT_LIST[[]]m4_divert(-1)FID_WR_DROP_LIST[[]]') +m4_define(FID_CLEANUP, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_CLEANUP(m4_eval($1+1),$2)]])') +m4_define(FID_WR_DPUT, `m4_undivert($1)') + +m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_CLEANUP(1,200)') m4_changequote([[,]]) From 63f49457dcc4216002742166dfecce751efa78d5 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 28 Jun 2019 11:08:48 +0200 Subject: [PATCH 65/88] Filter: renaming pointers for consistency The struct f_inst * is now always "what" and the union member pointer is always "whati". --- filter/decl.m4 | 52 ++++++++++++++++++++++--------------------------- filter/f-inst.c | 21 ++++++++++---------- filter/f-inst.h | 2 +- filter/f-util.c | 2 +- 4 files changed, 35 insertions(+), 42 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 88808973..925a7d9b 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -31,9 +31,6 @@ m4_divert(-1)m4_dnl # Final diversions # 200+ completed text before it is flushed to output -# Flush the completed instruction -m4_define(FID_END, `m4_divert(-1)') - m4_dnl m4_debugmode(aceflqtx) m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') @@ -58,8 +55,6 @@ m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_INTERPRET_BODY, `m4_divert(108)') m4_define(FID_ALL, `FID_INTERPRET_BODY'); - -m4_define(FID_ALL_TARGETS, `m4_ifdef([[FID_CURDIV]], [[m4_divert(FID_CURDIV)m4_undefine([[FID_CURDIV]])]])') m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], $1, TARGET, [[I]], $2, TARGET, [[C]], $3)') m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ @@ -84,14 +79,14 @@ FID_HIC( [[]], [[ { - struct f_inst *what_ = cfg_allocz(sizeof(struct f_inst)); - what_->fi_code = fi_code; - what_->lineno = ifs->lino; - what_->size = 1; - #define what (&(what_->i_]]INST_NAME()[[)) + struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); + what->fi_code = fi_code; + what->lineno = ifs->lino; + what->size = 1; + #define whati (&(what->i_]]INST_NAME()[[)) [[m4_undivert(103)]] - #undef what - return what_; + #undef whati + return what; } ]]) @@ -111,13 +106,13 @@ m4_undivert(104) FID_LINEARIZE case INST_NAME(): { -#define what (&(what_->i_]]INST_NAME()[[)) +#define whati (&(what->i_]]INST_NAME()[[)) #define item (&(dest->items[pos].i_]]INST_NAME()[[)) m4_undivert(105) -#undef what +#undef whati #undef item - dest->items[pos].fi_code = what_->fi_code; - dest->items[pos].lineno = what_->lineno; + dest->items[pos].fi_code = what->fi_code; + dest->items[pos].lineno = what->lineno; break; } m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) @@ -139,7 +134,6 @@ m4_undivert(108) #undef whati break; -FID_END ]])') m4_define(INST, `m4_dnl @@ -165,10 +159,10 @@ $1 $2; FID_NEW_ARGS , $1 $2 FID_NEW_BODY -what->$2 = $2; +whati->$2 = $2; m4_ifelse($3,,,[[ FID_LINEARIZE_BODY -item->$3 = what->$2; +item->$3 = whati->$2; ]]) m4_ifelse($4,,,[[ FID_SAME_BODY @@ -186,14 +180,14 @@ FID_ALL') m4_define(ARG_ANY, ` FID_STRUCT_IN -const struct f_inst * f$1; +struct f_inst * f$1; FID_NEW_ARGS -, const struct f_inst * f$1 +, struct f_inst * f$1 FID_NEW_BODY -what->f$1 = f$1; -for (const struct f_inst *child = f$1; child; child = child->next) what_->size += child->size; +whati->f$1 = f$1; +for (const struct f_inst *child = f$1; child; child = child->next) what->size += child->size; FID_LINEARIZE_BODY -pos = linearize(dest, what->f$1, pos);m4_dnl +pos = linearize(dest, whati->f$1, pos);m4_dnl FID_ALL()') m4_define(ARG, `ARG_ANY($1) @@ -220,11 +214,11 @@ const struct f_inst * f$1; FID_NEW_ARGS , const struct f_inst * f$1 FID_NEW_BODY -what->f$1 = f$1; +whati->f$1 = f$1; FID_DUMP_BODY f_dump_line(item->fl$1, indent + 1); FID_LINEARIZE_BODY -item->fl$1 = f_linearize(what->f$1); +item->fl$1 = f_linearize(whati->f$1); FID_SAME_BODY if (!f_same(f1->fl$1, f2->fl$1)) return 0; FID_INTERPRET_BODY @@ -307,10 +301,10 @@ FID_WR_PUT(7) /* Linearize */ static uint -linearize(struct f_line *dest, const struct f_inst *what_, uint pos) +linearize(struct f_line *dest, const struct f_inst *what, uint pos) { - for ( ; what_; what_ = what_->next) { - switch (what_->fi_code) { + for ( ; what; what = what->next) { + switch (what->fi_code) { FID_WR_PUT(8) } pos++; diff --git a/filter/f-inst.c b/filter/f-inst.c index 7349bf72..f033bea1 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -27,8 +27,8 @@ * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line * m4_dnl ECS; extended community subtype * m4_dnl COUNT(unused); simply a uint - * m4_dnl SYMBOL(unused); symbol handed from config - * m4_dnl FRET(unused); filter return value + * m4_dnl SYMBOL; symbol handed from config + * m4_dnl FRET; filter return value * m4_dnl STATIC_ATTR; static attribute definition * m4_dnl DYNAMIC_ATTR; dynamic attribute definition * m4_dnl RTC; route table config @@ -153,7 +153,7 @@ if (tt->fi_code != FI_CONSTANT) dyn++; - what->count = len; + whati->count = len; FID_ALL if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ @@ -262,8 +262,8 @@ /* Set to indirect value prepared in v1 */ INST(FI_VAR_SET, 1, 0) { - ARG_ANY(2); - SYMBOL(1); + ARG_ANY(1); + SYMBOL; if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID)) { /* IP->Quad implicit conversion */ @@ -294,17 +294,16 @@ FID_NEW_ARGS , const struct f_val val FID_NEW_BODY - what->val = val; + whati->val = val; FID_LINEARIZE_BODY - item->val = what->val; + item->val = whati->val; FID_SAME_BODY if (!val_same(&(f1->val), &(f2->val))) return 0; FID_DUMP_BODY debug("%svalue %s\n", INDENT, val_dump(&item->val)); FID_ALL - res = whati->val; - RESULT_OK; + RESULT_VAL(whati->val); } INST(FI_CONSTANT_DEFINED, 0, 1) { FID_STRUCT_IN @@ -315,9 +314,9 @@ FID_NEW_ARGS , const struct symbol *sym FID_NEW_BODY - what->sym = sym; + whati->sym = sym; FID_LINEARIZE_BODY - item->valp = (item->sym = what->sym)->val; + item->valp = (item->sym = whati->sym)->val; FID_SAME_BODY if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0; FID_DUMP_BODY diff --git a/filter/f-inst.h b/filter/f-inst.h index f0dcec64..2a2d050e 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -79,7 +79,7 @@ static inline struct f_line *f_linearize(const struct f_inst *root) void f_dump_line(const struct f_line *, uint indent); -struct filter *f_new_where(const struct f_inst *); +struct filter *f_new_where(struct f_inst *); static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .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) diff --git a/filter/f-util.c b/filter/f-util.c index 5500f282..4b580fb9 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -30,7 +30,7 @@ filter_name(const struct filter *filter) return filter->sym->name; } -struct filter *f_new_where(const struct f_inst *where) +struct filter *f_new_where(struct f_inst *where) { struct f_inst acc = { .fi_code = FI_PRINT_AND_DIE, From 236828d06f512b44457970795e44068d9d38ad3e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 1 Jul 2019 11:57:35 +0200 Subject: [PATCH 66/88] Filter: The interpreter code now shares its diversion with constructor This is a preparation for filter pre-evaluation. --- filter/decl.m4 | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 925a7d9b..50224abd 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -15,8 +15,7 @@ m4_divert(-1)m4_dnl # 8 linearize # 9 same (filter comparator) # 1 union in struct f_inst -# 3 constructors -# 10 interpreter +# 3 constructors + interpreter # # Per-inst Diversions: # 101 content of per-inst struct @@ -43,7 +42,6 @@ m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') m4_define(FID_SAME, `FID_ZONE(9, Comparison)') -m4_define(FID_INTERPRET, `FID_ZONE(10, Interpret)') m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') @@ -71,13 +69,23 @@ struct { m4_undivert(107) } i_[[]]INST_NAME(); FID_NEW -struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(102) -) FID_HIC( -[[;]], -[[]], [[ +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +[[m4_undivert(102)]] +);]], +[[ + case INST_NAME(): + #define whati (&(what->i_]]INST_NAME()[[)) + m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) + [[m4_undivert(108)]] + #undef whati + break; +]], +[[ +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +[[m4_undivert(102)]] +) { struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); what->fi_code = fi_code; @@ -126,14 +134,6 @@ m4_undivert(106) #undef f2 break; -FID_INTERPRET -case INST_NAME(): -#define whati (&(what->i_]]INST_NAME()[[)) -m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) -m4_undivert(108) -#undef whati -break; - ]])') m4_define(INST, `m4_dnl @@ -252,7 +252,7 @@ m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)') m4_changequote([[,]]) FID_WR_DIRECT(I) -FID_WR_PUT(10) +FID_WR_PUT(3) FID_WR_DIRECT(C) #include "nest/bird.h" #include "filter/filter.h" From f74d19765ea3fafdff8fd3443f50a7b309babe89 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 1 Jul 2019 12:07:06 +0200 Subject: [PATCH 67/88] Filter: Getting rid of RESULT_OK. Adding RESULT_VOID. This is a preparation for filter pre-evaluation. --- filter/decl.m4 | 4 ++-- filter/f-inst.c | 35 ++++++++++++++--------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 50224abd..77af84b3 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -227,9 +227,9 @@ do { if (whati->fl$1) { } } while(0)m4_dnl FID_ALL()') -m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()') m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') -m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') +m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; fstk->vcnt++; } while (0)FID_ALL()') +m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') diff --git a/filter/f-inst.c b/filter/f-inst.c index f033bea1..d48a6086 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -36,7 +36,8 @@ * m4_dnl ACCESS_RTE; this instruction needs route * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes * m4_dnl RESULT(type, union-field, value); putting this on value stack - * m4_dnl RESULT_OK; legalize what already is on the value stack + * m4_dnl RESULT_VAL(value-struct); pass the struct f_val directly + * m4_dnl RESULT_VOID; return undef * m4_dnl } * * Other code is just copied into the interpreter part. @@ -50,41 +51,37 @@ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i = v1.val.i + v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i + v2.val.i); } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i = v1.val.i - v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i - v2.val.i); } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i = v1.val.i * v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i * v2.val.i); } INST(FI_DIVIDE, 2, 1) { ARG(1,T_INT); ARG(2,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; - RESULT_OK; + RESULT(T_INT, i, v1.val.i / v2.val.i); } INST(FI_AND, 1, 1) { ARG(1,T_BOOL); - if (res.val.i) + if (v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_VAL(v1); } INST(FI_OR, 1, 1) { ARG(1,T_BOOL); - if (!res.val.i) + if (!v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_VAL(v1); } INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); @@ -281,8 +278,7 @@ INST(FI_VAR_GET, 0, 1) { SYMBOL(1); - res = fstk->vstk[curline.vbase + sym->offset]; - RESULT_OK; + RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]); } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -323,8 +319,7 @@ debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); FID_ALL - res = *whati->valp; - RESULT_OK; + RESULT_VAL(*whati->valp); } INST(FI_PRINT, 1, 0) { ARG_ANY(1); @@ -500,8 +495,7 @@ } /* Undefined value */ - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; } @@ -534,8 +528,7 @@ RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; default: bug("Unknown dynamic attribute type"); From 4212c0e7e5647e107e6e06238a417afc44fd7f75 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 1 Jul 2019 12:49:02 +0200 Subject: [PATCH 68/88] Filter: Moved f_inst allocation to separate function --- filter/decl.m4 | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 77af84b3..898b298d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -87,10 +87,7 @@ struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code [[m4_undivert(102)]] ) { - struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); - what->fi_code = fi_code; - what->lineno = ifs->lino; - what->size = 1; + struct f_inst *what = fi_new(fi_code); #define whati (&(what->i_]]INST_NAME()[[)) [[m4_undivert(103)]] #undef whati @@ -272,6 +269,16 @@ f_instruction_name(enum f_instruction_code fi) bug("Got unknown instruction code: %d", fi); } +static inline struct f_inst * +fi_new(enum f_instruction_code fi_code) +{ + struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); + what->lineno = ifs->lino; + what->size = 1; + what->fi_code = fi_code; + return what; +} + /* Instruction constructors */ FID_WR_PUT(3) From 26bfe59f450c2497dabc536c3e2a604e8aa5839a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 1 Jul 2019 13:13:06 +0200 Subject: [PATCH 69/88] Filter: Moved singleton member definitions to f-inst.c --- filter/decl.m4 | 14 +------------- filter/f-inst.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 898b298d..786fee31 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -140,14 +140,6 @@ m4_define([[INST_INVAL]], [[$2]])m4_dnl FID_ALL() m4_dnl ') -m4_dnl FID_MEMBER call: -m4_dnl type -m4_dnl name in f_inst -m4_dnl name in f_line_item -m4_dnl comparator for same -m4_dnl dump format string -m4_dnl dump format args -m4_dnl interpreter body m4_define(FID_MEMBER, `m4_dnl FID_LINE_IN $1 $2; @@ -230,15 +222,11 @@ m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') -m4_define(VAL, `FID_MEMBER(struct f_val $1, val, val m4_ifelse($1,,,[0]), [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val),)') -m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret), enum filter_return fret = whati->fret)') +m4_define(FRET, `') m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->ecs)') m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name, struct rtable *table = whati->rtc->table)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code,,, struct f_static_attr sa = whati->sa)') m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code,,, struct f_dynamic_attr da = whati->da)') -m4_define(COUNT, `FID_MEMBER(uint, count, count, f1->count != f2->count, number %u, item->count)') -m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree, const struct f_tree *tree = whati->tree)') -m4_define(STRING, `FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s)') m4_define(FID_WR_PUT_LIST) m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)') diff --git a/filter/f-inst.c b/filter/f-inst.c index d48a6086..ffe07738 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -20,21 +20,31 @@ * for several C sources; every instruction block gets expanded into many * different places. * + * All the arguments are processed literally; if you need an argument including comma, + * you have to quote it by [[ ... ]] + * * What is the syntax here? * m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args * m4_dnl ARG(num, type); argument, its id (in data fields) and type * m4_dnl ARG_ANY(num); argument with no type check * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line - * m4_dnl ECS; extended community subtype - * m4_dnl COUNT(unused); simply a uint * m4_dnl SYMBOL; symbol handed from config - * m4_dnl FRET; filter return value * m4_dnl STATIC_ATTR; static attribute definition * m4_dnl DYNAMIC_ATTR; dynamic attribute definition * m4_dnl RTC; route table config - * m4_dnl TREE; a tree * m4_dnl ACCESS_RTE; this instruction needs route * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes + * + * m4_dnl FID_MEMBER( custom instruction member + * m4_dnl C type, for storage in structs + * m4_dnl name in f_inst, how the member is named before linearization + * m4_dnl name in f_line_item, how the member is named afterwards + * m4_dnl comparator for same(), how the member is compared + * m4_dnl dump format string debug -> format string for bvsnprintf + * m4_dnl dump format args appropriate args + * m4_dnl interpreter body how to deal with this on execution + * m4_dnl ) + * * m4_dnl RESULT(type, union-field, value); putting this on value stack * m4_dnl RESULT_VAL(value-struct); pass the struct f_val directly * m4_dnl RESULT_VOID; return undef @@ -95,7 +105,8 @@ INST(FI_EC_CONSTRUCT, 2, 1) { ARG_ANY(1); ARG(2, T_INT); - ECS; + + FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->ecs); int check, ipv4_used; u32 key, val; @@ -141,7 +152,7 @@ INST(FI_PATHMASK_CONSTRUCT, 0, 1) { ARG_ANY(1); - COUNT(2); + FID_MEMBER(uint, count, count, f1->count != f2->count, number of items %u, item->count); FID_NEW_BODY uint len = 0; @@ -277,7 +288,7 @@ } INST(FI_VAR_GET, 0, 1) { - SYMBOL(1); + SYMBOL; RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]); } @@ -346,7 +357,7 @@ } FID_ALL - FRET(2); + FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret), enum filter_return fret = whati->fret); if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) && !(fs->flags & FF_SILENT)) @@ -789,7 +800,9 @@ INST(FI_SWITCH, 1, 0) { ARG_ANY(1); - TREE; + + FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree, const struct f_tree *tree = whati->tree); + const struct f_tree *t = find_tree(tree, &v1); if (!t) { v1.type = T_VOID; @@ -1034,7 +1047,8 @@ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ ARG(1, T_BOOL); - STRING; + FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s); + if (!bt_assert_hook) runtime("No bt_assert hook registered, can't assert"); From 30667d50417f926fc948905aaab3e679b416b2e1 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 1 Jul 2019 14:12:05 +0200 Subject: [PATCH 70/88] Filter: Resolving of defined constants in config time --- filter/config.Y | 2 +- filter/f-inst.c | 45 +++++++++------------------------------------ 2 files changed, 10 insertions(+), 37 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 72866bb0..ff2b966e 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -856,7 +856,7 @@ symbol_value: CF_SYM_KNOWN { switch ($1->class) { case SYM_CONSTANT_RANGE: - $$ = f_new_inst(FI_CONSTANT_DEFINED, $1); + $$ = f_new_inst(FI_CONSTANT, *($1->val)); break; case SYM_VARIABLE_RANGE: $$ = f_new_inst(FI_VAR_GET, $1); diff --git a/filter/f-inst.c b/filter/f-inst.c index ffe07738..a70a4a92 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -39,7 +39,7 @@ * m4_dnl C type, for storage in structs * m4_dnl name in f_inst, how the member is named before linearization * m4_dnl name in f_line_item, how the member is named afterwards - * m4_dnl comparator for same(), how the member is compared + * m4_dnl comparator for same(), if different, this should be TRUE (CAVEAT) * m4_dnl dump format string debug -> format string for bvsnprintf * m4_dnl dump format args appropriate args * m4_dnl interpreter body how to deal with this on execution @@ -294,44 +294,17 @@ /* some constants have value in a[1], some in *a[0].p, strange. */ INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */ - FID_LINE_IN - struct f_val val; - FID_STRUCT_IN - struct f_val val; - FID_NEW_ARGS - , const struct f_val val - FID_NEW_BODY - whati->val = val; - FID_LINEARIZE_BODY - item->val = whati->val; - FID_SAME_BODY - if (!val_same(&(f1->val), &(f2->val))) return 0; - FID_DUMP_BODY - debug("%svalue %s\n", INDENT, val_dump(&item->val)); - FID_ALL + FID_MEMBER( + struct f_val, + val, + val, + [[ !val_same(&(f1->val), &(f2->val)) ]], + value %s, + val_dump(&(item->val)) + ); RESULT_VAL(whati->val); } - INST(FI_CONSTANT_DEFINED, 0, 1) { - FID_STRUCT_IN - const struct symbol *sym; - FID_LINE_IN - const struct symbol *sym; - const struct f_val *valp; - FID_NEW_ARGS - , const struct symbol *sym - FID_NEW_BODY - whati->sym = sym; - FID_LINEARIZE_BODY - item->valp = (item->sym = whati->sym)->val; - FID_SAME_BODY - if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0; - FID_DUMP_BODY - debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); - FID_ALL - - RESULT_VAL(*whati->valp); - } INST(FI_PRINT, 1, 0) { ARG_ANY(1); val_format(&(v1), &fs->buf); From b40c0f028f37086991fefa9197708ba8c7b3d571 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 2 Jul 2019 10:45:53 +0200 Subject: [PATCH 71/88] Filter: Pre-evaluation of constant expressions --- conf/cf-lex.l | 1 + filter/Makefile | 3 +- filter/data.c | 9 ++++ filter/data.h | 3 +- filter/decl.m4 | 109 +++++++++++++++++++++++++++++----------------- filter/f-inst.c | 113 ++++++++++++++++++++++++++++++------------------ filter/filter.c | 13 +++--- lib/resource.h | 10 +++-- 8 files changed, 165 insertions(+), 96 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 0aa9273f..38250d90 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -757,6 +757,7 @@ cf_pop_scope(void) { conf_this_scope->active = 0; conf_this_scope = conf_this_scope->next; + ASSERT(conf_this_scope); } diff --git a/filter/Makefile b/filter/Makefile index b2f8d96d..c2062534 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -3,7 +3,8 @@ obj := $(src-o-files) $(all-daemon) $(cf-local) -M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) +#M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS)) +M4FLAGS_FILTERS=$(M4FLAGS) $(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp $(M4) $(M4FLAGS_FILTERS) -DTARGET=H -P $^ >$@ diff --git a/filter/data.c b/filter/data.c index 912e2b00..db55070f 100644 --- a/filter/data.c +++ b/filter/data.c @@ -514,6 +514,15 @@ val_format(const struct f_val *v, buffer *buf) } } +char * +val_format_str(struct linpool *lp, const struct f_val *v) { + buffer b; + LOG_BUFFER_INIT(b); + val_format(v, &b); + return lp_strdup(lp, b.start); +} + + static char val_dump_buffer[1024]; const char * val_dump(const struct f_val *v) { diff --git a/filter/data.h b/filter/data.h index 6973008f..083595f4 100644 --- a/filter/data.h +++ b/filter/data.h @@ -119,7 +119,7 @@ enum f_lval_type { struct f_lval { enum f_lval_type type; union { - const struct symbol *sym; + struct symbol *sym; struct f_dynamic_attr da; struct f_static_attr sa; }; @@ -169,6 +169,7 @@ void trie_format(const struct f_trie *t, buffer *buf); int val_same(const struct f_val *v1, const struct f_val *v2); int val_compare(const struct f_val *v1, const struct f_val *v2); void val_format(const struct f_val *v, buffer *buf); +char *val_format_str(struct linpool *lp, const struct f_val *v); const char *val_dump(const struct f_val *v); static inline int val_is_ip4(const struct f_val *v) diff --git a/filter/decl.m4 b/filter/decl.m4 index 786fee31..cc069485 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -53,7 +53,12 @@ m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_INTERPRET_BODY, `m4_divert(108)') m4_define(FID_ALL, `FID_INTERPRET_BODY'); -m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], $1, TARGET, [[I]], $2, TARGET, [[C]], $3)') +m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], [[$1]], TARGET, [[I]], [[$2]], TARGET, [[C]], [[$3]])') + +m4_define(FID_INTERPRET_EXEC, `FID_HIC(,[[FID_INTERPRET_BODY()]],[[m4_divert(-1)]])') +m4_define(FID_INTERPRET_NEW, `FID_HIC(,[[m4_divert(-1)]],[[FID_INTERPRET_BODY()]])') +m4_define(NEVER_CONSTANT, `m4_define([[INST_NEVER_CONSTANT]])') +m4_define(FID_IFCONST, `m4_ifdef([[INST_NEVER_CONSTANT]],[[$2]],[[$1]])') m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ FID_ENUM @@ -72,26 +77,29 @@ FID_NEW FID_HIC( [[ struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -[[m4_undivert(102)]] +m4_undivert(102) );]], [[ case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) - [[m4_undivert(108)]] + m4_undivert(108) #undef whati break; ]], [[ struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -[[m4_undivert(102)]] +m4_undivert(102) ) { struct f_inst *what = fi_new(fi_code); + FID_IFCONST([[uint constargs = 1;]]) #define whati (&(what->i_]]INST_NAME()[[)) - [[m4_undivert(103)]] + m4_undivert(103) + FID_IFCONST([[if (!constargs)]]) + return what; + FID_IFCONST([[m4_undivert(108)]]) #undef whati - return what; } ]]) @@ -130,13 +138,14 @@ m4_undivert(106) #undef f1 #undef f2 break; - +m4_divert(-1)FID_FLUSH(101,200) ]])') m4_define(INST, `m4_dnl INST_FLUSH()m4_dnl m4_define([[INST_NAME]], [[$1]])m4_dnl m4_define([[INST_INVAL]], [[$2]])m4_dnl +m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl FID_ALL() m4_dnl ') @@ -149,22 +158,18 @@ FID_NEW_ARGS , $1 $2 FID_NEW_BODY whati->$2 = $2; -m4_ifelse($3,,,[[ FID_LINEARIZE_BODY -item->$3 = whati->$2; +item->$2 = whati->$2; +m4_ifelse($3,,,[[ +FID_SAME_BODY +if ($3) return 0; ]]) m4_ifelse($4,,,[[ -FID_SAME_BODY -if ($4) return 0; -]]) -m4_ifelse($5,,,[[ FID_DUMP_BODY -debug("%s$5\n", INDENT, $6); -]]) -m4_ifelse($7,,,[[ -FID_INTERPRET_BODY -$7 +debug("%s$4\n", INDENT, $5); ]]) +FID_INTERPRET_EXEC +const $1 $2 = whati->$2 FID_ALL') m4_define(ARG_ANY, ` @@ -174,34 +179,39 @@ FID_NEW_ARGS , struct f_inst * f$1 FID_NEW_BODY whati->f$1 = f$1; -for (const struct f_inst *child = f$1; child; child = child->next) what->size += child->size; +for (const struct f_inst *child = f$1; child; child = child->next) { + what->size += child->size; +FID_IFCONST([[ + if (child->fi_code != FI_CONSTANT) + constargs = 0; +]]) +} FID_LINEARIZE_BODY -pos = linearize(dest, whati->f$1, pos);m4_dnl +pos = linearize(dest, whati->f$1, pos); FID_ALL()') m4_define(ARG, `ARG_ANY($1) -FID_INTERPRET_BODY +FID_INTERPRET_EXEC() if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl FID_ALL()') -m4_define(LINEX, `FID_INTERPRET_BODY -do { +m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_ALL()') +m4_define(LINEX_, `do { fstk->estk[fstk->ecnt].pos = 0; fstk->estk[fstk->ecnt].line = $1; fstk->estk[fstk->ecnt].ventry = fstk->vcnt; fstk->estk[fstk->ecnt].vbase = fstk->estk[fstk->ecnt-1].vbase; fstk->estk[fstk->ecnt].emask = 0; fstk->ecnt++; -} while (0)m4_dnl -FID_ALL()') +} while (0)') m4_define(LINE, ` FID_LINE_IN const struct f_line * fl$1; FID_STRUCT_IN -const struct f_inst * f$1; +struct f_inst * f$1; FID_NEW_ARGS -, const struct f_inst * f$1 +, struct f_inst * f$1 FID_NEW_BODY whati->f$1 = f$1; FID_DUMP_BODY @@ -210,23 +220,25 @@ FID_LINEARIZE_BODY item->fl$1 = f_linearize(whati->f$1); FID_SAME_BODY if (!f_same(f1->fl$1, f2->fl$1)) return 0; -FID_INTERPRET_BODY +FID_INTERPRET_EXEC do { if (whati->fl$1) { - LINEX(whati->fl$1); -} } while(0)m4_dnl + LINEX_(whati->fl$1); +} } while(0) +FID_INTERPRET_NEW +return whati->f$1 FID_ALL()') m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') -m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; fstk->vcnt++; } while (0)FID_ALL()') +m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]], +[[return fi_constant(what, $1)]])') m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') -m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, -[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') -m4_define(FRET, `') -m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->ecs)') -m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name, struct rtable *table = whati->rtc->table)') -m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code,,, struct f_static_attr sa = whati->sa)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code,,, struct f_dynamic_attr da = whati->da)') +m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, +[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') +m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') +m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') +m4_define(ACCESS_RTE, `NEVER_CONSTANT()') m4_define(FID_WR_PUT_LIST) m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)') @@ -267,8 +279,25 @@ fi_new(enum f_instruction_code fi_code) return what; } +static inline struct f_inst * +fi_constant(struct f_inst *what, struct f_val val) +{ + what->fi_code = FI_CONSTANT; + what->i_FI_CONSTANT.val = val; + return what; +} + +#define v1 whati->f1->i_FI_CONSTANT.val +#define v2 whati->f2->i_FI_CONSTANT.val +#define v3 whati->f3->i_FI_CONSTANT.val +#define runtime(fmt, ...) cf_error("filter preevaluation, line %d: " fmt, ifs->lino, ##__VA_ARGS__) +#define fpool cfg_mem +#define falloc(size) cfg_alloc(size) /* Instruction constructors */ FID_WR_PUT(3) +#undef v1 +#undef v2 +#undef v3 /* Line dumpers */ #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) @@ -387,9 +416,9 @@ FID_WR_PUT(3) m4_divert(-1) m4_changequote(`,') -m4_define(FID_CLEANUP, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_CLEANUP(m4_eval($1+1),$2)]])') +m4_define(FID_FLUSH, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_FLUSH(m4_eval($1+1),$2)]])') m4_define(FID_WR_DPUT, `m4_undivert($1)') -m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_CLEANUP(1,200)') +m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_FLUSH(1,200)') m4_changequote([[,]]) diff --git a/filter/f-inst.c b/filter/f-inst.c index a70a4a92..edc97794 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -37,12 +37,10 @@ * * m4_dnl FID_MEMBER( custom instruction member * m4_dnl C type, for storage in structs - * m4_dnl name in f_inst, how the member is named before linearization - * m4_dnl name in f_line_item, how the member is named afterwards + * m4_dnl name, how the member is named * m4_dnl comparator for same(), if different, this should be TRUE (CAVEAT) * m4_dnl dump format string debug -> format string for bvsnprintf * m4_dnl dump format args appropriate args - * m4_dnl interpreter body how to deal with this on execution * m4_dnl ) * * m4_dnl RESULT(type, union-field, value); putting this on value stack @@ -106,7 +104,7 @@ ARG_ANY(1); ARG(2, T_INT); - FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->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; @@ -152,24 +150,37 @@ INST(FI_PATHMASK_CONSTRUCT, 0, 1) { ARG_ANY(1); - FID_MEMBER(uint, count, count, f1->count != f2->count, number of items %u, item->count); + FID_MEMBER(uint, count, f1->count != f2->count, number of items %u, item->count); FID_NEW_BODY uint len = 0; - uint dyn = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) - if (tt->fi_code != FI_CONSTANT) - dyn++; + for (const struct f_inst *tt = f1; tt; tt = tt->next, len++); whati->count = len; + struct f_inst **items; + if (constargs) { + items = alloca(len * sizeof(struct f_inst *)); + for (uint i=0; f1; i++) { + items[i] = f1; + f1 = f1->next; + items[i]->next = 0; + } + whati->f1 = NULL; + } FID_ALL + FID_INTERPRET_EXEC if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); - struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); +#define pv fstk->vstk[fstk->vcnt - count + i] + + FID_INTERPRET_NEW +#define pv items[i]->i_FI_CONSTANT.val + + FID_INTERPRET_BODY + struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); for (uint i=0; icount; i++) { -#define pv fstk->vstk[fstk->vcnt - whati->count + i] switch (pv.type) { case T_PATH_MASK_ITEM: pm->item[i] = pv.val.pmi; @@ -185,9 +196,11 @@ } } - fstk->vcnt -= whati->count; - pm->len = whati->count; + FID_INTERPRET_EXEC + fstk->vcnt -= whati->count; + FID_ALL + pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); } @@ -270,8 +283,10 @@ /* Set to indirect value prepared in v1 */ INST(FI_VAR_SET, 1, 0) { + NEVER_CONSTANT; ARG_ANY(1); SYMBOL; + if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID)) { /* IP->Quad implicit conversion */ @@ -289,6 +304,7 @@ INST(FI_VAR_GET, 0, 1) { SYMBOL; + NEVER_CONSTANT; RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]); } @@ -297,26 +313,27 @@ FID_MEMBER( struct f_val, val, - val, [[ !val_same(&(f1->val), &(f2->val)) ]], value %s, val_dump(&(item->val)) ); - RESULT_VAL(whati->val); + RESULT_VAL(val); } INST(FI_PRINT, 1, 0) { + NEVER_CONSTANT; ARG_ANY(1); val_format(&(v1), &fs->buf); } INST(FI_CONDITION, 1, 0) { ARG(1, T_BOOL); - if (res.val.i) + if (v1.val.i) LINE(2,0); else LINE(3,1); } INST(FI_PRINT_AND_DIE, 0, 0) { + NEVER_CONSTANT; FID_LINEARIZE_BODY { uint opos = pos; @@ -330,7 +347,7 @@ } FID_ALL - FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret), enum filter_return fret = whati->fret); + FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret)); if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) && !(fs->flags & FF_SILENT)) @@ -663,7 +680,7 @@ runtime( "SADR expected" ); net_addr_ip6_sadr *net = (void *) v1.val.net; - net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6)); + net_addr *src = falloc(sizeof(net_addr_ip6)); net_fill_ip6(src, net->src_prefix, net->src_pxlen); RESULT(T_NET, net, src); @@ -721,6 +738,7 @@ } INST(FI_RETURN, 1, 1) { + NEVER_CONSTANT; /* Acquire the return value */ ARG_ANY(1); uint retpos = fstk->vcnt; @@ -748,6 +766,7 @@ } INST(FI_CALL, 0, 1) { + NEVER_CONSTANT; SYMBOL; /* Push the body on stack */ @@ -768,13 +787,14 @@ } INST(FI_DROP_RESULT, 1, 0) { + NEVER_CONSTANT; ARG_ANY(1); } INST(FI_SWITCH, 1, 0) { ARG_ANY(1); - FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree, const struct f_tree *tree = whati->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) { @@ -782,7 +802,7 @@ t = find_tree(tree, &v1); if (!t) { debug( "No else statement?\n"); - break; + FID_HIC(,break,return NULL); } } /* It is actually possible to have t->data NULL */ @@ -801,7 +821,7 @@ INST(FI_PATH_PREPEND, 2, 1) { /* Path prepend */ ARG(1, T_PATH); ARG(2, T_INT); - RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]); + RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]); } INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */ @@ -816,14 +836,14 @@ struct f_val dummy; if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) - RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, 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(fs->pool, 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(fs->pool, 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"); } @@ -834,11 +854,11 @@ 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(fs->pool, 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(fs->pool, 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) @@ -847,11 +867,11 @@ 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(fs->pool, 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(fs->pool, v1.val.ad, v2.val.lc) ]]); + RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]); } @@ -874,7 +894,7 @@ else runtime("Can't delete non-integer (set)"); - RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, 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) @@ -883,12 +903,12 @@ struct f_val dummy; if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) - RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, 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(fs->pool, 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(fs->pool, v1.val.ad, &v2, 0) ]]); + RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]); else runtime("Can't delete non-pair"); } @@ -897,22 +917,22 @@ { /* 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(fs->pool, 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(fs->pool, 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(fs->pool, 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(fs->pool, v1.val.ad, v2.val.lc) ]]); + RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]); } else @@ -927,7 +947,7 @@ u32 key = 0; if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT)) - RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, 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"); } @@ -938,7 +958,7 @@ 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(fs->pool, v1.val.ad, &v2, 1) ]]); + RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter pair"); } @@ -947,7 +967,7 @@ { /* 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(fs->pool, v1.val.ad, &v2, 1) ]]); + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter ec"); } @@ -956,7 +976,7 @@ { /* 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(fs->pool, v1.val.ad, &v2, 1) ]]); + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter lc"); } @@ -966,7 +986,9 @@ } 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; @@ -994,9 +1016,11 @@ } INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */ + NEVER_CONSTANT; ARG(1, T_NET); ARG(2, T_INT); RTC(3); + struct rtable *table = rtc->table; u32 as = v2.val.i; @@ -1015,15 +1039,18 @@ INST(FI_FORMAT, 1, 0) { /* Format */ ARG_ANY(1); - RESULT(T_STRING, s, val_format_str(fs, &v1)); + RESULT(T_STRING, s, val_format_str(fpool, &v1)); } INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ + NEVER_CONSTANT; ARG(1, T_BOOL); - FID_MEMBER(const char *, s, 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); if (!bt_assert_hook) runtime("No bt_assert hook registered, can't assert"); - bt_assert_hook(res.val.i, what); + bt_assert_hook(v1.val.i, what); } diff --git a/filter/filter.c b/filter/filter.c index ee29522e..ed0b21bc 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -150,14 +150,6 @@ f_rta_cow(struct filter_state *fs) f_cache_eattrs(fs); } -static char * -val_format_str(struct filter_state *fs, struct f_val *v) { - buffer b; - LOG_BUFFER_INIT(b); - val_format(v, &b); - return lp_strdup(fs->pool, b.start); -} - static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; /** @@ -215,6 +207,9 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) return F_ERROR; \ } while(0) +#define falloc(size) lp_alloc(fs->pool, size) +#define fpool fs->pool + #define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) @@ -224,6 +219,8 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #undef v2 #undef v3 #undef runtime +#undef falloc +#undef fpool #undef ACCESS_RTE #undef ACCESS_EATTRS } diff --git a/lib/resource.h b/lib/resource.h index d9d4bb8f..ad17d9ed 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -101,9 +101,13 @@ void buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_siz */ #define DMALLOC_DISABLE #include -#define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size) -#define xrealloc(size) _xrealloc_leap(__FILE__, __LINE__, size) -#define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr) +#define xmalloc(size) \ + dmalloc_malloc(__FILE__, __LINE__, (size), DMALLOC_FUNC_MALLOC, 0, 1) +#define xrealloc(ptr, size) \ + dmalloc_realloc(__FILE__, __LINE__, (ptr), (size), DMALLOC_FUNC_REALLOC, 1) +#define xfree(ptr) \ + dmalloc_free(__FILE__, __LINE__, (ptr), DMALLOC_FUNC_FREE) + #else /* * Unfortunately, several libraries we might want to link to define From c376555cecbfea83314e9f76bce5002185d3566a Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 2 Jul 2019 13:13:29 +0200 Subject: [PATCH 72/88] Filter: GCC, don't complain about indentation in generated code. --- filter/decl.m4 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/filter/decl.m4 b/filter/decl.m4 index cc069485..d1c51440 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -251,6 +251,12 @@ m4_changequote([[,]]) FID_WR_DIRECT(I) FID_WR_PUT(3) FID_WR_DIRECT(C) + +#if defined(__GNUC__) && __GNUC__ >= 6 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif + #include "nest/bird.h" #include "filter/filter.h" #include "filter/f-inst.h" @@ -382,6 +388,9 @@ FID_WR_PUT(9) return 1; } +#if defined(__GNUC__) && __GNUC__ >= 6 +#pragma GCC diagnostic pop +#endif FID_WR_DIRECT(H) /* Filter instruction codes */ From 550a6488c9e2241e2979317c04d6d73752618402 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 2 Jul 2019 17:39:56 +0200 Subject: [PATCH 73/88] Filter: documentation of the M4 preprocessor --- filter/decl.m4 | 351 +++++++++++++++++++++++++++++++----------------- filter/f-inst.c | 11 +- 2 files changed, 234 insertions(+), 128 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index cc069485..20119c1d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -6,149 +6,70 @@ m4_divert(-1)m4_dnl # # Can be freely distributed and used under the terms of the GNU GPL. # +# THIS IS A M4 MACRO FILE GENERATING 3 FILES ALTOGETHER. +# KEEP YOUR HANDS OFF UNLESS YOU KNOW WHAT YOU'RE DOING. +# EDITING AND DEBUGGING THIS FILE MAY DAMAGE YOUR BRAIN SERIOUSLY. # -# Global Diversions: -# 4 enum fi_code -# 5 enum fi_code to string -# 6 dump line item -# 7 dump line item callers -# 8 linearize -# 9 same (filter comparator) -# 1 union in struct f_inst -# 3 constructors + interpreter +# But you're welcome to read and edit and debug if you aren't scared. +# +# Uncomment the following line to get exhaustive debug output. +# m4_debugmode(aceflqtx) +# +# How it works: +# 1) Instruction to code conversion (uses diversions 100..199) +# 2) Code wrapping (uses diversions 1..99) +# 3) Final preparation (uses diversions 200..299) +# 4) Shipout +# +# See below for detailed description. +# +# +# 1) Instruction to code conversion +# The code provided in f-inst.c between consecutive INST() calls +# is interleaved for many different places. It is here processed +# and split into separate instances where split-by-instruction +# happens. These parts are stored in temporary diversions listed: # -# Per-inst Diversions: # 101 content of per-inst struct # 102 constructor arguments # 103 constructor body # 104 dump line item content +# (there may be nothing in dump-line content and +# it must be handled specially in phase 2) # 105 linearize body # 106 comparator body # 107 struct f_line_item content # 108 interpreter body # -# Final diversions -# 200+ completed text before it is flushed to output - -m4_dnl m4_debugmode(aceflqtx) - -m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') -m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)') -m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)') -m4_define(FID_NEW, `FID_ZONE(3, Constructor)') -m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') -m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') -m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') -m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') -m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') -m4_define(FID_SAME, `FID_ZONE(9, Comparison)') - +# Here are macros to allow you to _divert to the right directions. m4_define(FID_STRUCT_IN, `m4_divert(101)') m4_define(FID_NEW_ARGS, `m4_divert(102)') m4_define(FID_NEW_BODY, `m4_divert(103)') m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') -m4_define(FID_LINEARIZE_BODY, `m4_divert(105)m4_define([[FID_LINEARIZE_BODY_EXISTS]])') +m4_define(FID_LINEARIZE_BODY, `m4_divert(105)') m4_define(FID_SAME_BODY, `m4_divert(106)') m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_INTERPRET_BODY, `m4_divert(108)') -m4_define(FID_ALL, `FID_INTERPRET_BODY'); +# Sometimes you want slightly different code versions in different +# outputs. +# Use FID_HIC(code for inst-gen.h, code for inst-gen.c, code for inst-interpret.c) +# and put it into [[ ]] quotes if it shall contain commas. m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], [[$1]], TARGET, [[I]], [[$2]], TARGET, [[C]], [[$3]])') +# In interpreter code, this is quite common. m4_define(FID_INTERPRET_EXEC, `FID_HIC(,[[FID_INTERPRET_BODY()]],[[m4_divert(-1)]])') m4_define(FID_INTERPRET_NEW, `FID_HIC(,[[m4_divert(-1)]],[[FID_INTERPRET_BODY()]])') + +# If the instruction is never converted to constant, the interpret +# code is not produced at all for constructor m4_define(NEVER_CONSTANT, `m4_define([[INST_NEVER_CONSTANT]])') m4_define(FID_IFCONST, `m4_ifdef([[INST_NEVER_CONSTANT]],[[$2]],[[$1]])') -m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -FID_ENUM -INST_NAME(), -FID_ENUM_STR -[INST_NAME()] = "INST_NAME()", -FID_INST -struct { -m4_undivert(101) -} i_[[]]INST_NAME(); -FID_LINE -struct { -m4_undivert(107) -} i_[[]]INST_NAME(); -FID_NEW -FID_HIC( -[[ -struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(102) -);]], -[[ - case INST_NAME(): - #define whati (&(what->i_]]INST_NAME()[[)) - m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) - m4_undivert(108) - #undef whati - break; -]], -[[ -struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(102) -) - { - struct f_inst *what = fi_new(fi_code); - FID_IFCONST([[uint constargs = 1;]]) - #define whati (&(what->i_]]INST_NAME()[[)) - m4_undivert(103) - FID_IFCONST([[if (!constargs)]]) - return what; - FID_IFCONST([[m4_undivert(108)]]) - #undef whati - } -]]) - -FID_DUMP_CALLER -case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; - -FID_DUMP -m4_ifdef([[FID_DUMP_BODY_EXISTS]], -[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]], -[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) -m4_undefine([[FID_DUMP_BODY_EXISTS]]) -{ -#define item (&(item_->i_]]INST_NAME()[[)) -m4_undivert(104) -#undef item -} - -FID_LINEARIZE -case INST_NAME(): { -#define whati (&(what->i_]]INST_NAME()[[)) -#define item (&(dest->items[pos].i_]]INST_NAME()[[)) - m4_undivert(105) -#undef whati -#undef item - dest->items[pos].fi_code = what->fi_code; - dest->items[pos].lineno = what->lineno; - break; -} -m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) - -FID_SAME -case INST_NAME(): -#define f1 (&(f1_->i_]]INST_NAME()[[)) -#define f2 (&(f2_->i_]]INST_NAME()[[)) -m4_undivert(106) -#undef f1 -#undef f2 -break; -m4_divert(-1)FID_FLUSH(101,200) -]])') - -m4_define(INST, `m4_dnl -INST_FLUSH()m4_dnl -m4_define([[INST_NAME]], [[$1]])m4_dnl -m4_define([[INST_INVAL]], [[$2]])m4_dnl -m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl -FID_ALL() m4_dnl -') - +# If the instruction has some attributes (here called members), +# these are typically carried with the instruction from constructor +# to interpreter. This yields a line of code everywhere on the path. +# FID_MEMBER is a macro to help with this task. m4_define(FID_MEMBER, `m4_dnl FID_LINE_IN $1 $2; @@ -170,8 +91,14 @@ debug("%s$4\n", INDENT, $5); ]]) FID_INTERPRET_EXEC const $1 $2 = whati->$2 -FID_ALL') +FID_INTERPRET_BODY') +# Instruction arguments are needed only until linearization is done. +# This puts the arguments into the filter line to be executed before +# the instruction itself. +# +# To achieve this, ARG_ANY must be called before anything writes into +# the instruction line as it moves the instruction pointer forward. m4_define(ARG_ANY, ` FID_STRUCT_IN struct f_inst * f$1; @@ -188,14 +115,17 @@ FID_IFCONST([[ } FID_LINEARIZE_BODY pos = linearize(dest, whati->f$1, pos); -FID_ALL()') +FID_INTERPRET_BODY()') +# Some arguments need to check their type. After that, ARG_ANY is called. m4_define(ARG, `ARG_ANY($1) FID_INTERPRET_EXEC() if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl -FID_ALL()') +FID_INTERPRET_BODY()') -m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_ALL()') +# Executing another filter line. This replaces the recursion +# that was needed in the former implementation. +m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()') m4_define(LINEX_, `do { fstk->estk[fstk->ecnt].pos = 0; fstk->estk[fstk->ecnt].line = $1; @@ -226,13 +156,16 @@ do { if (whati->fl$1) { } } while(0) FID_INTERPRET_NEW return whati->f$1 -FID_ALL()') +FID_INTERPRET_BODY()') +# Some of the instructions have a result. These constructions +# state the result and put it to the right place. m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]], [[return fi_constant(what, $1)]])') m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') +# Some common filter instruction members m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') @@ -240,13 +173,174 @@ m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') m4_define(ACCESS_RTE, `NEVER_CONSTANT()') +# 2) Code wrapping +# The code produced in 1xx temporary diversions is a raw code without +# any auxiliary commands and syntactical structures around. When the +# instruction is done, INST_FLUSH is called. More precisely, it is called +# at the beginning of INST() call and at the end of file. +# +# INST_FLUSH picks all the temporary diversions, wraps their content +# into appropriate headers and structures and saves them into global +# diversions listed: +# +# 4 enum fi_code +# 5 enum fi_code to string +# 6 dump line item +# 7 dump line item callers +# 8 linearize +# 9 same (filter comparator) +# 1 union in struct f_inst +# 3 constructors + interpreter +# +# These global diversions contain blocks of code that can be directly +# put into the final file, yet it still can't be written out now as +# every instruction writes to all of these diversions. + +# Code wrapping diversion names +m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') +m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)') +m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)') +m4_define(FID_NEW, `FID_ZONE(3, Constructor)') +m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') +m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') +m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') +m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') +m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') +m4_define(FID_SAME, `FID_ZONE(9, Comparison)') + +# This macro does all the code wrapping. See inline comments. +m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ +FID_ENUM m4_dnl Contents of enum fi_code { ... } +INST_NAME(), +FID_ENUM_STR m4_dnl Contents of const char * indexed by enum fi_code +[INST_NAME()] = "INST_NAME()", +FID_INST m4_dnl Anonymous structure inside struct f_inst +struct { +m4_undivert(101) +} i_[[]]INST_NAME(); +FID_LINE m4_dnl Anonymous structure inside struct f_line_item +struct { +m4_undivert(107) +} i_[[]]INST_NAME(); +FID_NEW m4_dnl Constructor and interpreter code together +FID_HIC( +[[ m4_dnl Public declaration of constructor in H file +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +m4_undivert(102) +);]], +[[ m4_dnl The one case in The Big Switch inside interpreter + case INST_NAME(): + #define whati (&(what->i_]]INST_NAME()[[)) + m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) + m4_undivert(108) + #undef whati + break; +]], +[[ m4_dnl Constructor itself +struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code +m4_undivert(102) +) + { + /* Allocate the structure */ + struct f_inst *what = fi_new(fi_code); + FID_IFCONST([[uint constargs = 1;]]) + + /* Initialize all the members */ + #define whati (&(what->i_]]INST_NAME()[[)) + m4_undivert(103) + + /* If not constant, return the instruction itself */ + FID_IFCONST([[if (!constargs)]]) + return what; + + /* Try to pre-calculate the result */ + FID_IFCONST([[m4_undivert(108)]]) + #undef whati + } +]]) + +FID_DUMP_CALLER m4_dnl Case in another big switch used in instruction dumping (debug) +case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; + +FID_DUMP m4_dnl The dumper itself +m4_ifdef([[FID_DUMP_BODY_EXISTS]], +[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]], +[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) +m4_undefine([[FID_DUMP_BODY_EXISTS]]) +{ +#define item (&(item_->i_]]INST_NAME()[[)) +m4_undivert(104) +#undef item +} + +FID_LINEARIZE m4_dnl The linearizer +case INST_NAME(): { +#define whati (&(what->i_]]INST_NAME()[[)) +#define item (&(dest->items[pos].i_]]INST_NAME()[[)) + m4_undivert(105) +#undef whati +#undef item + dest->items[pos].fi_code = what->fi_code; + dest->items[pos].lineno = what->lineno; + break; +} + +FID_SAME m4_dnl This code compares two f_line"s while reconfiguring +case INST_NAME(): +#define f1 (&(f1_->i_]]INST_NAME()[[)) +#define f2 (&(f2_->i_]]INST_NAME()[[)) +m4_undivert(106) +#undef f1 +#undef f2 +break; + +m4_divert(-1)FID_FLUSH(101,200) m4_dnl And finally this flushes all the unused diversions +]])') + +m4_define(INST, `m4_dnl This macro is called on beginning of each instruction. +INST_FLUSH()m4_dnl First, old data is flushed +m4_define([[INST_NAME]], [[$1]])m4_dnl Then we store instruction name, +m4_define([[INST_INVAL]], [[$2]])m4_dnl instruction input value count +m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl and reset NEVER_CONSTANT trigger. +FID_INTERPRET_BODY() m4_dnl By default, every code is interpreter code. +') + +# 3) Final preparation +# +# Now we prepare all the code around the global diversions. +# It must be here, not in m4wrap, as we want M4 to mark the code +# by #line directives correctly, not to claim that every single line +# is at the beginning of the m4wrap directive. +# +# This part is split by the final file. +# H for inst-gen.h +# I for inst-interpret.c +# C for inst-gen.c +# +# So we in cycle: +# A. open a diversion +# B. send there some code +# C. close that diversion +# D. flush a global diversion +# E. open another diversion and goto B. +# +# Final diversions +# 200+ completed text before it is flushed to output + +# This is a list of output diversions m4_define(FID_WR_PUT_LIST) + +# This macro does the steps C to E, see before. m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)') +# These macros do the splitting between H/I/C m4_define(FID_WR_DIRECT, `m4_ifelse(TARGET,[[$1]],[[FID_WR_INIT()]],[[FID_WR_STOP()]])') m4_define(FID_WR_INIT, `m4_define([[FID_WR_DIDX]],200)m4_define([[FID_WR_PUT]],[[FID_WR_PUT_ALSO($]][[@)]])m4_divert(200)') m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)') +# Here is the direct code to be put into the output files +# together with the undiversions, being hidden under FID_WR_PUT() + m4_changequote([[,]]) FID_WR_DIRECT(I) FID_WR_PUT(3) @@ -412,13 +506,24 @@ struct f_line_item { /* Instruction constructors */ FID_WR_PUT(3) - m4_divert(-1) + +# 4) Shipout +# +# Everything is prepared in FID_WR_PUT_LIST now. Let's go! + m4_changequote(`,') +# Flusher auxiliary macro m4_define(FID_FLUSH, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_FLUSH(m4_eval($1+1),$2)]])') + +# Defining the macro used in FID_WR_PUT_LIST m4_define(FID_WR_DPUT, `m4_undivert($1)') +# After the code is read and parsed, we: m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_FLUSH(1,200)') m4_changequote([[,]]) +# And now M4 is going to parse f-inst.c, fill the diversions +# and after the file is done, the content of m4_m4wrap (see before) +# is executed. diff --git a/filter/f-inst.c b/filter/f-inst.c index edc97794..5f30ee38 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -167,7 +167,7 @@ } whati->f1 = NULL; } - FID_ALL + FID_INTERPRET_BODY FID_INTERPRET_EXEC if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ @@ -198,7 +198,7 @@ FID_INTERPRET_EXEC fstk->vcnt -= whati->count; - FID_ALL + FID_INTERPRET_BODY pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); @@ -337,7 +337,7 @@ FID_LINEARIZE_BODY { uint opos = pos; - FID_ALL + FID_INTERPRET_BODY ARG_ANY(1); @@ -345,7 +345,7 @@ if (opos < pos) dest->items[pos].flags |= FIF_PRINTED; } - FID_ALL + FID_INTERPRET_BODY FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret)); @@ -1045,7 +1045,8 @@ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */ 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); From 84c58aabd0d7a6a3d1508de004a29fd22423fde6 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 2 Jul 2019 17:59:21 +0200 Subject: [PATCH 74/88] Filter: Nicer whitespaces in generated inst-gen.h --- filter/decl.m4 | 93 +++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 20119c1d..26a1a166 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -71,12 +71,12 @@ m4_define(FID_IFCONST, `m4_ifdef([[INST_NEVER_CONSTANT]],[[$2]],[[$1]])') # to interpreter. This yields a line of code everywhere on the path. # FID_MEMBER is a macro to help with this task. m4_define(FID_MEMBER, `m4_dnl -FID_LINE_IN -$1 $2; -FID_STRUCT_IN -$1 $2; -FID_NEW_ARGS -, $1 $2 +FID_LINE_IN()m4_dnl + $1 $2; +FID_STRUCT_IN()m4_dnl + $1 $2; +FID_NEW_ARGS()m4_dnl + , $1 $2 FID_NEW_BODY whati->$2 = $2; FID_LINEARIZE_BODY @@ -100,10 +100,10 @@ FID_INTERPRET_BODY') # To achieve this, ARG_ANY must be called before anything writes into # the instruction line as it moves the instruction pointer forward. m4_define(ARG_ANY, ` -FID_STRUCT_IN -struct f_inst * f$1; -FID_NEW_ARGS -, struct f_inst * f$1 +FID_STRUCT_IN()m4_dnl + struct f_inst * f$1; +FID_NEW_ARGS()m4_dnl + , struct f_inst * f$1 FID_NEW_BODY whati->f$1 = f$1; for (const struct f_inst *child = f$1; child; child = child->next) { @@ -136,12 +136,12 @@ m4_define(LINEX_, `do { } while (0)') m4_define(LINE, ` -FID_LINE_IN -const struct f_line * fl$1; -FID_STRUCT_IN -struct f_inst * f$1; -FID_NEW_ARGS -, struct f_inst * f$1 +FID_LINE_IN()m4_dnl + const struct f_line * fl$1; +FID_STRUCT_IN()m4_dnl + struct f_inst * f$1; +FID_NEW_ARGS()m4_dnl + , struct f_inst * f$1 FID_NEW_BODY whati->f$1 = f$1; FID_DUMP_BODY @@ -166,8 +166,7 @@ m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]], m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') # Some common filter instruction members -m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, -[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') +m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') @@ -196,8 +195,10 @@ m4_define(ACCESS_RTE, `NEVER_CONSTANT()') # put into the final file, yet it still can't be written out now as # every instruction writes to all of these diversions. -# Code wrapping diversion names -m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') +# Code wrapping diversion names. Here we want an explicit newline +# after the C comment. +m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */ +') m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)') m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)') m4_define(FID_NEW, `FID_ZONE(3, Constructor)') @@ -210,25 +211,25 @@ m4_define(FID_SAME, `FID_ZONE(9, Comparison)') # This macro does all the code wrapping. See inline comments. m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ -FID_ENUM m4_dnl Contents of enum fi_code { ... } -INST_NAME(), -FID_ENUM_STR m4_dnl Contents of const char * indexed by enum fi_code -[INST_NAME()] = "INST_NAME()", -FID_INST m4_dnl Anonymous structure inside struct f_inst -struct { -m4_undivert(101) -} i_[[]]INST_NAME(); -FID_LINE m4_dnl Anonymous structure inside struct f_line_item -struct { -m4_undivert(107) -} i_[[]]INST_NAME(); -FID_NEW m4_dnl Constructor and interpreter code together +FID_ENUM()m4_dnl Contents of enum fi_code { ... } + INST_NAME(), +FID_ENUM_STR()m4_dnl Contents of const char * indexed by enum fi_code + [INST_NAME()] = "INST_NAME()", +FID_INST()m4_dnl Anonymous structure inside struct f_inst + struct { +m4_undivert(101)m4_dnl + } i_[[]]INST_NAME(); +FID_LINE()m4_dnl Anonymous structure inside struct f_line_item + struct { +m4_undivert(107)m4_dnl + } i_[[]]INST_NAME(); +FID_NEW()m4_dnl Constructor and interpreter code together FID_HIC( -[[ m4_dnl Public declaration of constructor in H file +[[m4_dnl Public declaration of constructor in H file struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(102) +m4_undivert(102)m4_dnl );]], -[[ m4_dnl The one case in The Big Switch inside interpreter +[[m4_dnl The one case in The Big Switch inside interpreter case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) @@ -236,7 +237,7 @@ m4_undivert(102) #undef whati break; ]], -[[ m4_dnl Constructor itself +[[m4_dnl Constructor itself struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code m4_undivert(102) ) @@ -259,10 +260,10 @@ m4_undivert(102) } ]]) -FID_DUMP_CALLER m4_dnl Case in another big switch used in instruction dumping (debug) +FID_DUMP_CALLER()m4_dnl Case in another big switch used in instruction dumping (debug) case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; -FID_DUMP m4_dnl The dumper itself +FID_DUMP()m4_dnl The dumper itself m4_ifdef([[FID_DUMP_BODY_EXISTS]], [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]], [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) @@ -273,7 +274,7 @@ m4_undivert(104) #undef item } -FID_LINEARIZE m4_dnl The linearizer +FID_LINEARIZE()m4_dnl The linearizer case INST_NAME(): { #define whati (&(what->i_]]INST_NAME()[[)) #define item (&(dest->items[pos].i_]]INST_NAME()[[)) @@ -285,7 +286,7 @@ case INST_NAME(): { break; } -FID_SAME m4_dnl This code compares two f_line"s while reconfiguring +FID_SAME()m4_dnl This code compares two f_line"s while reconfiguring case INST_NAME(): #define f1 (&(f1_->i_]]INST_NAME()[[)) #define f2 (&(f2_->i_]]INST_NAME()[[)) @@ -294,7 +295,7 @@ m4_undivert(106) #undef f2 break; -m4_divert(-1)FID_FLUSH(101,200) m4_dnl And finally this flushes all the unused diversions +m4_divert(-1)FID_FLUSH(101,200)m4_dnl And finally this flushes all the unused diversions ]])') m4_define(INST, `m4_dnl This macro is called on beginning of each instruction. @@ -302,7 +303,7 @@ INST_FLUSH()m4_dnl First, old data is flushed m4_define([[INST_NAME]], [[$1]])m4_dnl Then we store instruction name, m4_define([[INST_INVAL]], [[$2]])m4_dnl instruction input value count m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl and reset NEVER_CONSTANT trigger. -FID_INTERPRET_BODY() m4_dnl By default, every code is interpreter code. +FID_INTERPRET_BODY()m4_dnl By default, every code is interpreter code. ') # 3) Final preparation @@ -480,7 +481,7 @@ FID_WR_PUT(9) FID_WR_DIRECT(H) /* Filter instruction codes */ enum f_instruction_code { -FID_WR_PUT(4) +FID_WR_PUT(4)m4_dnl } PACKED; /* Filter instruction structure for config */ @@ -490,7 +491,7 @@ struct f_inst { int size; /* How many instructions are underneath */ int lineno; /* Line number */ union { - FID_WR_PUT(1) +FID_WR_PUT(1)m4_dnl }; }; @@ -500,7 +501,7 @@ struct f_line_item { enum f_instruction_flags flags; /* Flags, instruction-specific */ uint lineno; /* Where */ union { - FID_WR_PUT(2) +FID_WR_PUT(2)m4_dnl }; }; From 263fa2c4a6bf226172a6aef9a6b8198a5901c5bf Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 2 Jul 2019 22:57:00 +0200 Subject: [PATCH 75/88] Filter: Dropped some more irrelevant whitespace from generated files --- filter/decl.m4 | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index 26a1a166..42515c13 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -77,19 +77,19 @@ FID_STRUCT_IN()m4_dnl $1 $2; FID_NEW_ARGS()m4_dnl , $1 $2 -FID_NEW_BODY +FID_NEW_BODY()m4_dnl whati->$2 = $2; -FID_LINEARIZE_BODY +FID_LINEARIZE_BODY()m4_dnl item->$2 = whati->$2; m4_ifelse($3,,,[[ -FID_SAME_BODY +FID_SAME_BODY()m4_dnl if ($3) return 0; ]]) m4_ifelse($4,,,[[ -FID_DUMP_BODY +FID_DUMP_BODY()m4_dnl debug("%s$4\n", INDENT, $5); ]]) -FID_INTERPRET_EXEC +FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 FID_INTERPRET_BODY') @@ -119,7 +119,7 @@ FID_INTERPRET_BODY()') # Some arguments need to check their type. After that, ARG_ANY is called. m4_define(ARG, `ARG_ANY($1) -FID_INTERPRET_EXEC() +FID_INTERPRET_EXEC()m4_dnl if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl FID_INTERPRET_BODY()') @@ -142,19 +142,19 @@ FID_STRUCT_IN()m4_dnl struct f_inst * f$1; FID_NEW_ARGS()m4_dnl , struct f_inst * f$1 -FID_NEW_BODY +FID_NEW_BODY()m4_dnl whati->f$1 = f$1; -FID_DUMP_BODY +FID_DUMP_BODY()m4_dnl f_dump_line(item->fl$1, indent + 1); -FID_LINEARIZE_BODY +FID_LINEARIZE_BODY()m4_dnl item->fl$1 = f_linearize(whati->f$1); -FID_SAME_BODY +FID_SAME_BODY()m4_dnl if (!f_same(f1->fl$1, f2->fl$1)) return 0; -FID_INTERPRET_EXEC +FID_INTERPRET_EXEC()m4_dnl do { if (whati->fl$1) { LINEX_(whati->fl$1); } } while(0) -FID_INTERPRET_NEW +FID_INTERPRET_NEW()m4_dnl return whati->f$1 FID_INTERPRET_BODY()') @@ -233,13 +233,13 @@ m4_undivert(102)m4_dnl case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) - m4_undivert(108) + m4_undivert(108)m4_dnl #undef whati break; ]], [[m4_dnl Constructor itself struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code -m4_undivert(102) +m4_undivert(102)m4_dnl ) { /* Allocate the structure */ @@ -248,14 +248,14 @@ m4_undivert(102) /* Initialize all the members */ #define whati (&(what->i_]]INST_NAME()[[)) - m4_undivert(103) + m4_undivert(103)m4_dnl /* If not constant, return the instruction itself */ FID_IFCONST([[if (!constargs)]]) return what; /* Try to pre-calculate the result */ - FID_IFCONST([[m4_undivert(108)]]) + FID_IFCONST([[m4_undivert(108)]])m4_dnl #undef whati } ]]) @@ -270,7 +270,7 @@ m4_ifdef([[FID_DUMP_BODY_EXISTS]], m4_undefine([[FID_DUMP_BODY_EXISTS]]) { #define item (&(item_->i_]]INST_NAME()[[)) -m4_undivert(104) +m4_undivert(104)m4_dnl #undef item } @@ -278,7 +278,7 @@ FID_LINEARIZE()m4_dnl The linearizer case INST_NAME(): { #define whati (&(what->i_]]INST_NAME()[[)) #define item (&(dest->items[pos].i_]]INST_NAME()[[)) - m4_undivert(105) + m4_undivert(105)m4_dnl #undef whati #undef item dest->items[pos].fi_code = what->fi_code; @@ -290,7 +290,7 @@ FID_SAME()m4_dnl This code compares two f_line"s while reconfiguring case INST_NAME(): #define f1 (&(f1_->i_]]INST_NAME()[[)) #define f2 (&(f2_->i_]]INST_NAME()[[)) -m4_undivert(106) +m4_undivert(106)m4_dnl #undef f1 #undef f2 break; From 78976974e711e52c3b8fa6a80b290cf2fa4f692d Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 3 Jul 2019 00:00:11 +0200 Subject: [PATCH 76/88] Dynamic attributes definition split whether it is bitmask or not. --- filter/f-inst.h | 6 +++-- filter/f-util.c | 2 +- nest/config.Y | 2 +- proto/babel/config.Y | 2 +- proto/bgp/config.Y | 24 +++++++++--------- proto/ospf/config.Y | 8 +++--- proto/radv/config.Y | 4 +-- proto/rip/config.Y | 4 +-- sysdep/linux/netlink.Y | 56 +++++++++++++++++++++--------------------- sysdep/unix/krt.Y | 4 +-- 10 files changed, 57 insertions(+), 55 deletions(-) diff --git a/filter/f-inst.h b/filter/f-inst.h index 2a2d050e..58a60f0f 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -80,8 +80,10 @@ static inline struct f_line *f_linearize(const struct f_inst *root) void f_dump_line(const struct f_line *, uint indent); struct filter *f_new_where(struct f_inst *); -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, 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 = type, .bit = bit, .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(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 }; } struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); diff --git a/filter/f-util.c b/filter/f-util.c index 4b580fb9..b4105aad 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -174,7 +174,7 @@ ca_lookup(pool *p, const char *name, int f_type) } cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1); - cas->fda = f_new_dynamic_attr(ea_type, 0, f_type, EA_CUSTOM(id)); + cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id)); cas->uc = 1; strcpy(cas->name, name); diff --git a/nest/config.Y b/nest/config.Y index e4dedc66..430c9f29 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -791,7 +791,7 @@ proto_patt2: | TEXT { $$.ptr = $1; $$.patt = 1; } ; -dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_GEN_IGP_METRIC); } ; +dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ; CF_CODE diff --git a/proto/babel/config.Y b/proto/babel/config.Y index 78175323..b6bc70fa 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -125,7 +125,7 @@ babel_iface_opt_list: babel_iface: babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish; -dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_BABEL_METRIC); } ; +dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BABEL_METRIC); } ; CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index f9e5efaf..ac8d024a 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -272,29 +272,29 @@ bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; dynamic_attr: BGP_ORIGIN - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; dynamic_attr: BGP_PATH - { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, 0, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; dynamic_attr: BGP_NEXT_HOP - { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; dynamic_attr: BGP_MED - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; dynamic_attr: BGP_LOCAL_PREF - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; dynamic_attr: BGP_ATOMIC_AGGR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, 0, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; dynamic_attr: BGP_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; dynamic_attr: BGP_ORIGINATOR_ID - { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; dynamic_attr: BGP_CLUSTER_LIST - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; dynamic_attr: BGP_EXT_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, 0, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; dynamic_attr: BGP_LARGE_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, 0, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 66cf60c1..2e9ed0ac 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -498,10 +498,10 @@ ospf_iface: ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } ; -dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC1); } ; -dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC2); } ; -dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_TAG); } ; -dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ; +dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ; +dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ; +dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ; +dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ; CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); CF_CLI(SHOW OSPF, optproto, [], [[Show information about OSPF protocol]]) diff --git a/proto/radv/config.Y b/proto/radv/config.Y index b8eeb439..53715f77 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -332,8 +332,8 @@ radv_sensitive: | SENSITIVE bool { $$ = $2; } ; -dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; -dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RA_LIFETIME); } ; +dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; +dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ; CF_CODE diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 4ab793d1..5b5f94a0 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -186,8 +186,8 @@ rip_iface: rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish; -dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_METRIC); } ; -dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_TAG); } ; +dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ; +dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ; CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index 8f0a91c1..7097f577 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -26,39 +26,39 @@ kern_sys_item: | METRIC expr { THIS_KRT->sys.metric = $2; } ; -dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_KRT_PREFSRC); } ; -dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REALM); } ; -dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SCOPE); } ; +dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ; +dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ; +dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ; -dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_MTU); } ; -dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_WINDOW); } ; -dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTT); } ; -dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTTVAR); } ; -dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SSTRESH); } ; -dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_CWND); } ; -dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_ADVMSS); } ; -dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REORDERING); } ; -dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_HOPLIMIT); } ; -dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITCWND); } ; -dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTO_MIN); } ; -dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITRWND); } ; -dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_QUICKACK); } ; +dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ; +dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ; +dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ; +dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ; +dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ; +dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ; +dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ; +dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ; +dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ; +dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ; +dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ; +dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ; +dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ; /* Bits of EA_KRT_LOCK, based on RTAX_* constants */ -dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 2, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 4, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 5, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 6, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 7, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 8, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 9, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 10, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 13, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, T_BOOL, EA_KRT_LOCK); } ; +dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, T_BOOL, EA_KRT_LOCK); } ; -dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 0, T_BOOL, EA_KRT_FEATURES); } ; -dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_FEATURES); } ; +dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, T_BOOL, EA_KRT_FEATURES); } ; +dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(3, T_BOOL, EA_KRT_FEATURES); } ; CF_CODE diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index e3f6271c..95b54d65 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -122,8 +122,8 @@ kif_iface: kif_iface_start iface_patt_list_nopx kif_iface_opt_list; -dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SOURCE); } ; -dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_METRIC); } ; +dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SOURCE); } ; +dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_METRIC); } ; CF_CODE From 3265c9169dfc185ccdb787c6c83d9d8e2d0429c1 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 3 Jul 2019 00:04:24 +0200 Subject: [PATCH 77/88] Removed obsolete comment at as_path_cut() --- nest/a-path.c | 1 - 1 file changed, 1 deletion(-) diff --git a/nest/a-path.c b/nest/a-path.c index 62369af3..a1b7c42f 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -271,7 +271,6 @@ as_path_to_old(struct linpool *pool, const struct adata *path) /* * Cut the path to the length @num, measured to the usual path metric. Note that * AS_CONFED_* segments have zero length and must be added if they are on edge. - * In contrast to other as_path_* functions, @path is modified in place. */ struct adata * as_path_cut(struct linpool *pool, const struct adata *path, uint num) From 0206c070ace90c48a806a74fac52ba6e6ff9858b Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 3 Jul 2019 01:23:49 +0200 Subject: [PATCH 78/88] Filter: Split printing and dying --- conf/confbase.Y | 4 +++- filter/config.Y | 51 ++++++++++++++++++++++++++++++++++--------------- filter/decl.m4 | 19 ++++++++++++++++++ filter/f-inst.c | 43 ++++++++++++++++++++++------------------- filter/f-util.c | 8 ++++---- 5 files changed, 85 insertions(+), 40 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index bcfd3f1a..775af22d 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -64,7 +64,9 @@ CF_DECLS struct rtable_config *r; struct channel_config *cc; struct f_inst *x; - struct f_inst *xp[2]; + struct { + struct f_inst *begin, *end; + } xp; enum filter_return fret; enum ec_subtype ecs; struct f_dynamic_attr fda; diff --git a/filter/config.Y b/filter/config.Y index ff2b966e..c40f28d4 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -447,7 +447,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc ELSE %type cmds_int -%type term block cmd cmds constant constructor print_one print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail +%type term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter where_filter @@ -621,11 +621,21 @@ function_def: /* Programs */ cmds: /* EMPTY */ { $$ = NULL; } - | cmds_int { $$ = $1[0]; } + | cmds_int { $$ = $1.begin; } ; -cmds_int: cmd { $$[0] = $$[1] = $1; } - | cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; } +cmds_int: cmd { + $$.begin = $$.end = $1; + while ($$.end->next) + $$.end = $$.end->next; + } + | cmds_int cmd { + $$.begin = $1.begin; + $1.end->next = $2; + $$.end = $2; + while ($$.end->next) + $$.end = $$.end->next; + } ; block: @@ -960,17 +970,13 @@ break_command: | PRINTN { $$ = F_NONL; } ; -print_one: - term { $$ = f_new_inst(FI_PRINT, $1); } - ; - print_list: /* EMPTY */ { $$ = NULL; } - | print_one { $$ = $1; } - | print_one ',' print_list { - if ($1) { - $1->next = $3; - $$ = $1; - } else $$ = $3; + | term { $$ = $1; } + | term ',' print_list { + ASSERT($1); + ASSERT($1->next == NULL); + $1->next = $3; + $$ = $1; } ; @@ -1011,7 +1017,22 @@ cmd: | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); } - | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); } + | break_command print_list ';' { + struct f_inst *breaker = NULL; + struct f_inst *printer = NULL; + if ($2) + printer = f_new_inst(FI_PRINT, $2); + if ($1 != F_NONL) + breaker = f_new_inst(FI_DIE, $1); + + if (printer && breaker) + printer->next = breaker; + + if (printer) + $$ = printer; + else + $$ = breaker; + } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } | CASE term '{' switch_body '}' { $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); diff --git a/filter/decl.m4 b/filter/decl.m4 index 42515c13..9bd9a140 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -93,6 +93,25 @@ FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 FID_INTERPRET_BODY') +m4_define(FID_MEMBER_IN, `m4_dnl +FID_LINE_IN()m4_dnl + $1 $2; +FID_STRUCT_IN()m4_dnl + $1 $2; +FID_LINEARIZE_BODY()m4_dnl +item->$2 = whati->$2; +m4_ifelse($3,,,[[ +FID_SAME_BODY()m4_dnl +if ($3) return 0; +]]) +m4_ifelse($4,,,[[ +FID_DUMP_BODY()m4_dnl +debug("%s$4\n", INDENT, $5); +]]) +FID_INTERPRET_EXEC()m4_dnl +const $1 $2 = whati->$2 +FID_INTERPRET_BODY') + # Instruction arguments are needed only until linearization is done. # This puts the arguments into the filter line to be executed before # the instruction itself. diff --git a/filter/f-inst.c b/filter/f-inst.c index 5f30ee38..8d5c6656 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -173,7 +173,7 @@ if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); -#define pv fstk->vstk[fstk->vcnt - count + i] +#define pv fstk->vstk[fstk->vcnt - whati->count + i] FID_INTERPRET_NEW #define pv items[i]->i_FI_CONSTANT.val @@ -320,11 +320,6 @@ RESULT_VAL(val); } - INST(FI_PRINT, 1, 0) { - NEVER_CONSTANT; - ARG_ANY(1); - val_format(&(v1), &fs->buf); - } INST(FI_CONDITION, 1, 0) { ARG(1, T_BOOL); if (v1.val.i) @@ -332,28 +327,37 @@ else LINE(3,1); } - INST(FI_PRINT_AND_DIE, 0, 0) { + + INST(FI_PRINT, 0, 0) { NEVER_CONSTANT; - FID_LINEARIZE_BODY - { - uint opos = pos; - FID_INTERPRET_BODY - ARG_ANY(1); + FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count); + + FID_NEW_BODY + uint len = 0; + for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) + ; + whati->count = len; - FID_LINEARIZE_BODY - if (opos < pos) - dest->items[pos].flags |= FIF_PRINTED; - } FID_INTERPRET_BODY +#define pv fstk->vstk[fstk->vcnt - whati->count + i] + if (whati->count) + for (uint i=0; icount; i++) + val_format(&(pv), &fs->buf); +#undef pv + + fstk->vcnt -= whati->count; + } + + INST(FI_DIE, 0, 0) { + NEVER_CONSTANT; FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret)); - if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) && - !(fs->flags & FF_SILENT)) + if (fs->buf.start < fs->buf.pos) log_commit(*L_INFO, &fs->buf); - switch (fret) { + switch (whati->fret) { case F_QUITBIRD: die( "Filter asked me to die" ); case F_ACCEPT: @@ -361,7 +365,6 @@ case F_ERROR: case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */ return fret; /* We have to return now, no more processing. */ - case F_NONL: case F_NOP: break; default: diff --git a/filter/f-util.c b/filter/f-util.c index b4105aad..e61949f2 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -33,17 +33,17 @@ filter_name(const struct filter *filter) struct filter *f_new_where(struct f_inst *where) { struct f_inst acc = { - .fi_code = FI_PRINT_AND_DIE, + .fi_code = FI_DIE, .lineno = ifs->lino, .size = 1, - .i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, }, + .i_FI_DIE = { .fret = F_ACCEPT, }, }; struct f_inst rej = { - .fi_code = FI_PRINT_AND_DIE, + .fi_code = FI_DIE, .lineno = ifs->lino, .size = 1, - .i_FI_PRINT_AND_DIE = { .fret = F_REJECT, }, + .i_FI_DIE = { .fret = F_REJECT, }, }; struct f_inst i = { From 84ac62d3967f5294f4dc208b803a273a101744a8 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 3 Jul 2019 08:13:07 +0200 Subject: [PATCH 79/88] Filter: CLI command to dump all the linearized filters --- filter/filter.c | 38 ++++++++++++++++++++++++++++++++++++++ filter/filter.h | 6 ++++-- nest/config.Y | 2 ++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index ed0b21bc..d9c98872 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -482,3 +482,41 @@ filter_commit(struct config *new, struct config *old) break; } } + +void filters_dump_all(void) +{ + struct symbol *sym; + WALK_LIST(sym, config->symbols) { + switch (sym->class) { + case SYM_FILTER: + debug("Named filter %s:\n", sym->name); + f_dump_line(sym->filter->root, 1); + break; + case SYM_FUNCTION: + debug("Function %s:\n", sym->name); + f_dump_line(sym->function, 1); + break; + case SYM_PROTO: + { + debug("Protocol %s:\n", sym->name); + struct channel *c; + WALK_LIST(c, sym->proto->proto->channels) { + debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]); + if (c->in_filter == FILTER_ACCEPT) + debug(" ALL\n"); + else if (c->in_filter == FILTER_REJECT) + debug(" NONE\n"); + else if (c->in_filter == FILTER_UNDEF) + debug(" UNDEF\n"); + else if (c->in_filter->sym) { + ASSERT(c->in_filter->sym->filter == c->in_filter); + debug(" named filter %s\n", c->in_filter->sym->name); + } else { + debug("\n"); + f_dump_line(c->in_filter->root, 2); + } + } + } + } + } +} diff --git a/filter/filter.h b/filter/filter.h index 36b63e7c..9d997efb 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -64,9 +64,11 @@ int f_same(const struct f_line *f1, const struct f_line *f2); void filter_commit(struct config *new, struct config *old); +void filters_dump_all(void); + #define FILTER_ACCEPT NULL -#define FILTER_REJECT ((void *) 1) -#define FILTER_UNDEF ((void *) 2) /* Used in BGP */ +#define FILTER_REJECT ((struct filter *) 1) +#define FILTER_UNDEF ((struct filter *) 2) /* Used in BGP */ #define FF_SILENT 2 /* Silent filter execution */ diff --git a/nest/config.Y b/nest/config.Y index 430c9f29..e97b8fb3 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -731,6 +731,8 @@ CF_CLI(DUMP ROUTES,,, [[Dump routing table]]) { rt_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { protos_dump_all(); cli_msg(0, ""); } ; +CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]]) +{ filters_dump_all(); cli_msg(0, ""); } ; CF_CLI(EVAL, term, , [[Evaluate an expression]]) { cmd_eval(f_linearize($2)); } ; From bfa15a642f8e262af5c18ba5898597a20bdf4e2f Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 10 Jul 2019 16:46:31 +0200 Subject: [PATCH 80/88] Filter: Minor cleanups --- filter/f-inst.c | 44 +++++++++++++++++++++++++++----------------- filter/filter.c | 12 ++++++------ 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 8d5c6656..685bd426 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -91,6 +91,7 @@ else RESULT_VAL(v1); } + INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); @@ -100,6 +101,7 @@ runtime( "Can't operate with value out of bounds in pair constructor" ); RESULT(T_PAIR, i, (u1 << 16) | u2); } + INST(FI_EC_CONSTRUCT, 2, 1) { ARG_ANY(1); ARG(2, T_INT); @@ -120,7 +122,7 @@ ipv4_used = 1; key = ipa_to_u32(v1.val.ip); } else - runtime("Argument 1 of instruction FI_EC_CONSTRUCT must be integer or IPv4 address, got 0x%02x"); + runtime("Argument 1 of EC constructor must be integer or IPv4 address, got 0x%02x", v1.type); val = v2.val.i; @@ -173,21 +175,21 @@ if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); -#define pv fstk->vstk[fstk->vcnt - whati->count + i] +#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] FID_INTERPRET_NEW -#define pv items[i]->i_FI_CONSTANT.val +#define pv(i) items[i]->i_FI_CONSTANT.val FID_INTERPRET_BODY struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); for (uint i=0; icount; i++) { - switch (pv.type) { + switch (pv(i).type) { case T_PATH_MASK_ITEM: - pm->item[i] = pv.val.pmi; + pm->item[i] = pv(i).val.pmi; break; case T_INT: pm->item[i] = (struct f_path_mask_item) { - .asn = pv.val.i, + .asn = pv(i).val.i, .kind = PM_ASN, }; break; @@ -195,6 +197,7 @@ runtime( "Error resolving path mask template: value not an integer" ); } } +#undef pv FID_INTERPRET_EXEC fstk->vcnt -= whati->count; @@ -295,7 +298,7 @@ .type = T_QUAD, .val.i = ipa_to_u32(v1.val.ip), }; - else + else runtime( "Assigning to variable of incompatible type" ); } @@ -308,8 +311,7 @@ RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]); } - /* some constants have value in a[1], some in *a[0].p, strange. */ - INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */ + INST(FI_CONSTANT, 0, 1) { FID_MEMBER( struct f_val, val, @@ -320,6 +322,7 @@ RESULT_VAL(val); } + INST(FI_CONDITION, 1, 0) { ARG(1, T_BOOL); if (v1.val.i) @@ -341,10 +344,10 @@ FID_INTERPRET_BODY -#define pv fstk->vstk[fstk->vcnt - whati->count + i] +#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] if (whati->count) for (uint i=0; icount; i++) - val_format(&(pv), &fs->buf); + val_format(&(pv(i)), &fs->buf); #undef pv fstk->vcnt -= whati->count; @@ -371,8 +374,8 @@ bug( "unknown return type: Can't happen"); } } - - INST(FI_RTA_GET, 0, 1) { /* rta access */ + + INST(FI_RTA_GET, 0, 1) { { STATIC_ATTR; ACCESS_RTE; @@ -577,6 +580,7 @@ case EAF_TYPE_OPAQUE: 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" ); @@ -586,11 +590,13 @@ (* (ip_addr *) ad->data) = v1.val.ip; l->attrs[0].u.ptr = ad; break; + case EAF_TYPE_AS_PATH: if (v1.type != T_PATH) runtime( "Setting path attribute to non-path value" ); 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" ); @@ -605,22 +611,27 @@ l->attrs[0].u.data = data & ~(1u << da.bit); } 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 type in e,S"); + + default: + bug("Unknown dynamic attribute type"); } f_rta_cow(fs); @@ -728,7 +739,7 @@ RESULT(T_INT, i, as); } - INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */ + INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */ ARG(1, T_PATH); int as = 0; as_path_get_last(v1.val.ad, &as); @@ -754,7 +765,6 @@ if (!fstk->ecnt) if (fstk->vstk[retpos].type == T_BOOL) if (fstk->vstk[retpos].val.i) - return F_ACCEPT; else return F_REJECT; @@ -775,7 +785,7 @@ /* Push the body on stack */ LINEX(sym->function); curline.emask |= FE_RETURN; - + /* Before this instruction was called, there was the T_VOID * automatic return value pushed on value stack and also * sym->function->args function arguments. Setting the diff --git a/filter/filter.c b/filter/filter.c index d9c98872..beb2457d 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -181,7 +181,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) /* The same as with the value stack. Not resetting the stack for performance reasons. */ fstk->ecnt = 1; - fstk->estk[0].line = line; + fstk->estk[0].line = line; fstk->estk[0].pos = 0; #define curline fstk->estk[fstk->ecnt-1] @@ -225,7 +225,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #undef ACCESS_EATTRS } } - + /* End of current line. Drop local variables before exiting. */ fstk->vcnt -= curline.line->vars; fstk->vcnt -= curline.line->args; @@ -335,7 +335,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i } /** - * f_eval_rte – run a filter line for an uncached route + * f_eval_rte - run a filter line for an uncached route * @expr: filter line to run * @rte: route being filtered, may be modified * @tmp_pool: all filter allocations go from this pool @@ -364,7 +364,7 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool } /* - * f_eval – get a value of a term + * f_eval - get a value of a term * @expr: filter line containing the term * @tmp_pool: long data may get allocated from this pool * @pres: here the output will be stored @@ -383,7 +383,7 @@ f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) } /* - * f_eval_int – get an integer value of a term + * f_eval_int - get an integer value of a term * Called internally from the config parser, uses its internal memory pool * for allocations. Do not call in other cases. */ @@ -409,7 +409,7 @@ f_eval_int(const struct f_line *expr) } /* - * f_eval_buf – get a value of a term and print it to the supplied buffer + * f_eval_buf - get a value of a term and print it to the supplied buffer */ enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf) From 547be53b8cefc6d346cf13dcedb3e527c3472b06 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 12:03:13 +0200 Subject: [PATCH 81/88] Filter: Don't fail badly when trying to access non-existent route in config time --- filter/decl.m4 | 2 +- filter/filter.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index aa4ab576..b1cdaf0d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -189,7 +189,7 @@ m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2-> m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') -m4_define(ACCESS_RTE, `NEVER_CONSTANT()') +m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())') # 2) Code wrapping # The code produced in 1xx temporary diversions is a raw code without diff --git a/filter/filter.c b/filter/filter.c index beb2457d..089618f4 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -210,7 +210,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define falloc(size) lp_alloc(fs->pool, size) #define fpool fs->pool -#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) #include "filter/inst-interpret.c" @@ -221,7 +220,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #undef runtime #undef falloc #undef fpool -#undef ACCESS_RTE #undef ACCESS_EATTRS } } @@ -400,7 +398,7 @@ f_eval_int(const struct f_line *expr) LOG_BUFFER_INIT(filter_state.buf); if (interpret(&filter_state, expr, &val) > F_RETURN) - cf_error("Runtime error while evaluating expression"); + cf_error("Runtime error while evaluating expression; see log for details"); if (val.type != T_INT) cf_error("Integer expression expected"); From 1b9db6d4a7d8ab9f3ada5d21f8f05c3c8bf3c2e2 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 12:03:47 +0200 Subject: [PATCH 82/88] Filter: Don't write out when re-evaluating filter for internal purposes. --- filter/f-inst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index 685bd426..c0badeab 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -345,7 +345,7 @@ FID_INTERPRET_BODY #define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] - if (whati->count) + if (whati->count && !(fs->flags & FF_SILENT)) for (uint i=0; icount; i++) val_format(&(pv(i)), &fs->buf); #undef pv From 0da06b7103a5601fb7c224ab82a6d3799cb55308 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 13:19:01 +0200 Subject: [PATCH 83/88] Filter: lots of documentation --- filter/f-inst.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- filter/f-inst.h | 34 +---------- filter/filter.c | 17 ++---- 3 files changed, 156 insertions(+), 49 deletions(-) diff --git a/filter/f-inst.c b/filter/f-inst.c index c0badeab..7d41efe6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -7,7 +7,42 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * - * Filter instructions. You shall define your instruction only here + * The filter code goes through several phases: + * + * 1 Parsing + * Flex- and Bison-generated parser decodes the human-readable data into + * a struct f_inst tree. This is an infix tree that was interpreted by + * depth-first search execution in previous versions of the interpreter. + * All instructions have their constructor: f_new_inst(FI_EXAMPLE, ...) + * translates into f_new_inst_FI_EXAMPLE(...) and the types are checked in + * compile time. If the result of the instruction is always the same, + * it's reduced to FI_CONSTANT directly in constructor. This phase also + * counts how many instructions are underlying in means of f_line_item + * fields to know how much we have to allocate in the next phase. + * + * 2 Linearize before interpreting + * The infix tree is always interpreted in the same order. Therefore we + * sort the instructions one after another into struct f_line. Results + * and arguments of these instructions are implicitly put on a value + * stack; e.g. the + operation just takes two arguments from the value + * stack and puts the result on there. + * + * 3 Interpret + * The given line is put on a custom execution stack. If needed (FI_CALL, + * FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top + * of the stack; when that line finishes, the execution continues on the + * older lines on the stack where it stopped before. + * + * 4 Same + * On config reload, the filters have to be compared whether channel + * reload is needed or not. The comparison is done by comparing the + * struct f_line's recursively. + * + * The main purpose of this rework was to improve filter performance + * by making the interpreter non-recursive. + * + * The other outcome is concentration of instruction definitions to + * one place -- right here. You shall define your instruction only here * and nowhere else. * * Beware. This file is interpreted by M4 macros. These macros @@ -48,11 +83,122 @@ * m4_dnl RESULT_VOID; return undef * m4_dnl } * + * Also note that the { ... } blocks are not respected by M4 at all. + * If you get weird unmatched-brace-pair errors, check what it generated and why. + * What is really considered as one instruction is not the { ... } block + * after m4_dnl INST() but all the code between them. + * * Other code is just copied into the interpreter part. * - * If you want to write something really special, see FI_CALL - * or FI_CONSTANT or whatever else to see how to use the FID_* - * macros. + * If you are satisfied with this, you don't need to read the following + * detailed description of what is really done with the instruction definitions. + * + * m4_dnl Now let's look under the cover. The code between each INST() + * m4_dnl is copied to several places, namely these (numbered by the M4 diversions + * m4_dnl used in filter/decl.m4): + * + * m4_dnl (102) struct f_inst *f_new_inst(FI_EXAMPLE [[ put it here ]]) + * m4_dnl { + * m4_dnl ... (common code) + * m4_dnl (103) [[ put it here ]] + * m4_dnl ... + * m4_dnl if (all arguments are constant) + * 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. + * m4_dnl For constant pre-interpretation (108), see below at FID_INTERPRET_BODY. + * + * m4_dnl struct f_inst { + * m4_dnl ... (common fields) + * m4_dnl union { + * m4_dnl struct { + * m4_dnl (101) [[ put it here ]] + * m4_dnl } i_FI_EXAMPLE; + * m4_dnl ... + * m4_dnl }; + * m4_dnl }; + * m4_dnl This structure is returned from constructor. + * m4_dnl For writing directly to this structure, use FID_STRUCT_IN. + * + * m4_dnl linearize(struct f_line *dest, const struct f_inst *what, uint pos) { + * m4_dnl ... + * m4_dnl switch (what->fi_code) { + * m4_dnl case FI_EXAMPLE: + * m4_dnl (105) [[ put it here ]] + * m4_dnl break; + * m4_dnl } + * m4_dnl } + * m4_dnl This is called when translating from struct f_inst to struct f_line_item. + * m4_dnl For accessing your custom instruction data, use following macros: + * m4_dnl whati -> for accessing (struct f_inst).i_FI_EXAMPLE + * m4_dnl item -> for accessing (struct f_line)[pos].i_FI_EXAMPLE + * m4_dnl For writing directly here, use FID_LINEARIZE_BODY. + * + * m4_dnl (107) struct f_line_item { + * m4_dnl ... (common fields) + * m4_dnl union { + * m4_dnl struct { + * m4_dnl (101) [[ put it here ]] + * m4_dnl } i_FI_EXAMPLE; + * m4_dnl ... + * m4_dnl }; + * m4_dnl }; + * m4_dnl The same as FID_STRUCT_IN (101) but for the other structure. + * m4_dnl This structure is returned from the linearizer (105). + * m4_dnl For writing directly to this structure, use FID_LINE_IN. + * + * m4_dnl f_dump_line_item_FI_EXAMPLE(const struct f_line_item *item, const int indent) + * m4_dnl { + * m4_dnl (104) [[ put it here ]] + * m4_dnl } + * m4_dnl This code dumps the instruction on debug. Note that the argument + * m4_dnl is the linearized instruction; if the instruction has arguments, + * m4_dnl their code has already been linearized and their value is taken + * m4_dnl from the value stack. + * m4_dnl For writing directly here, use FID_DUMP_BODY. + * + * m4_dnl f_same(...) + * m4_dnl { + * m4_dnl switch (f1_->fi_code) { + * m4_dnl case FI_EXAMPLE: + * m4_dnl (106) [[ put it here ]] + * m4_dnl break; + * m4_dnl } + * m4_dnl } + * m4_dnl This code compares the two given instrucions (f1_ and f2_) + * m4_dnl on reconfigure. For accessing your custom instruction data, + * m4_dnl use macros f1 and f2. + * m4_dnl For writing directly here, use FID_SAME_BODY. + * + * m4_dnl interpret(...) + * m4_dnl { + * m4_dnl switch (what->fi_code) { + * m4_dnl case FI_EXAMPLE: + * m4_dnl (108) [[ put it here ]] + * m4_dnl break; + * m4_dnl } + * m4_dnl } + * m4_dnl This code executes the instruction. Every pre-defined macro + * m4_dnl resets the output here. For setting it explicitly, + * m4_dnl use FID_INTERPRET_BODY. + * m4_dnl This code is put on two places; one is the interpreter, the other + * m4_dnl is instruction constructor. If you need to distinguish between + * m4_dnl these two, use FID_INTERPRET_EXEC or FID_INTERPRET_NEW respectively. + * m4_dnl To address the difference between interpreter and constructor + * m4_dnl environments, there are several convenience macros defined: + * m4_dnl runtime() -> for spitting out runtime error like division by zero + * m4_dnl RESULT(...) -> declare result; may overwrite arguments + * m4_dnl v1, v2, v3 -> positional arguments, may be overwritten by RESULT() + * m4_dnl falloc(size) -> allocate memory from the appropriate linpool + * m4_dnl fpool -> the current linpool + * m4_dnl NEVER_CONSTANT-> don't generate pre-interpretation code at all + * m4_dnl ACCESS_RTE -> check that route is available, also NEVER_CONSTANT + * m4_dnl ACCESS_EATTRS -> pre-cache the eattrs; use only with ACCESS_RTE + * m4_dnl f_rta_cow(fs) -> function to call before any change to route should be done + * + * m4_dnl If you are stymied, see FI_CALL or FI_CONSTANT or just search for + * m4_dnl the mentioned macros in this file to see what is happening there in wild. */ /* Binary operators */ diff --git a/filter/f-inst.h b/filter/f-inst.h index 58a60f0f..33fcf4a9 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -7,39 +7,7 @@ * Can be freely distributed and used under the terms of the GNU GPL. * * Filter interpreter data structures and internal API. - * The filter code goes through several phases: - * - * 1 Parsing - * Flex- and Bison-generated parser decodes the human-readable data into - * a struct f_inst tree. This is an infix tree that was interpreted by - * depth-first search execution in previous versions of the interpreter. - * All instructions have their constructor: f_new_inst(FI_code, ...) - * translates into f_new_inst_FI_code(...) and the types are checked in - * compile time. - * - * 2 Linearize before interpreting - * The infix tree is always interpreted in the same order. Therefore we - * sort the instructions one after another into struct f_line. Results - * and arguments of these instructions are implicitly put on a value - * stack; e.g. the + operation just takes two arguments from the value - * stack and puts the result on there. - * - * 3 Interpret - * The given line is put on a custom execution stack. If needed (FI_CALL, - * FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top - * of the stack; when that line finishes, the execution continues on the - * older lines on the stack where it stopped before. - * - * 4 Same - * On config reload, the filters have to be compared whether channel - * reload is needed or not. The comparison is done by comparing the - * struct f_line's recursively. - * - * The main purpose of this rework was to improve filter performance - * by making the interpreter non-recursive. - * - * The other outcome is concentration of instruction definitions to - * one place -- filter/f-inst.c + * See filter/f-inst.c for documentation. */ #ifndef _BIRD_F_INST_H_ diff --git a/filter/filter.c b/filter/filter.c index 089618f4..0d727449 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -15,20 +15,13 @@ * the source from user into a tree of &f_inst structures. These trees are * later interpreted using code in |filter/filter.c|. * - * A filter is represented by a tree of &f_inst structures, one structure per - * "instruction". Each &f_inst contains @code, @aux value which is - * usually the data type this instruction operates on and two generic - * arguments (@a[0], @a[1]). Some instructions contain pointer(s) to other - * instructions in their (@a[0], @a[1]) fields. + * A filter is represented by a tree of &f_inst structures, later translated + * into lists called &f_line. All the instructions are defined and documented + * in |filter/f-inst.c| definition file. * * Filters use a &f_val structure for their data. Each &f_val - * contains type and value (types are constants prefixed with %T_). Few - * of the types are special; %T_RETURN can be or-ed with a type to indicate - * that return from a function or from the whole filter should be - * forced. Important thing about &f_val's is that they may be copied - * with a simple |=|. That's fine for all currently defined types: strings - * are read-only (and therefore okay), paths are copied for each - * operation (okay too). + * contains type and value (types are constants prefixed with %T_). + * Look into |filter/data.h| for more information and appropriate calls. */ #undef LOCAL_DEBUG From c29d73a06a8052f653e85f6472c663f70f6706cc Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 15:06:52 +0200 Subject: [PATCH 84/88] Filter: fixed excessive stack allocation in functions with args but no local vars --- filter/config.Y | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index c40f28d4..f3e83cfd 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -453,7 +453,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type filter where_filter %type filter_body function_body %type lvalue -%type type function_params declsn decls +%type type function_args function_vars %type ec_kind %type break_command %type cnum @@ -553,25 +553,30 @@ type: } ; -/* Declarations with ';' at the end */ -decls: - /* EMPTY */ { $$ = 0; } - | declsn ';' { $$ = $1; } +function_argsn: + /* EMPTY */ + | function_argsn type CF_SYM_VOID ';' { + if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed"); + cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); + } ; -/* Declarations that have no ';' at the end. */ -declsn: - type CF_SYM_VOID { - cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++); - $$ = $2->scope->slots; - } - | declsn ';' type CF_SYM_VOID { - if ($4->scope->slots >= 0xff) cf_error("Too many declarations, at most 255 allowed"); +function_args: + '(' ')' { $$ = 0; } + | '(' function_argsn type CF_SYM_VOID ')' { cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++); $$ = $4->scope->slots; } ; +function_vars: + /* EMPTY */ { $$ = 0; } + | function_vars type CF_SYM_VOID ';' { + cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); + $$ = $1 + 1; + } + ; + filter_body: function_body ; filter: @@ -593,13 +598,8 @@ where_filter: } ; -function_params: - '(' declsn ')' { $$ = $2; } - | '(' ')' { $$ = 0; } - ; - function_body: - decls '{' cmds '}' { + function_vars '{' cmds '}' { $$ = f_linearize($3); $$->vars = $1; } @@ -610,8 +610,8 @@ function_def: FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope($2); - } function_params function_body { - $5->vars -= $4; + } function_args function_body { + DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars); $5->args = $4; $2->function = $5; cf_pop_scope(); From c0999a149c223fa9c622552a314c767e6a640bf6 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 15:12:18 +0200 Subject: [PATCH 85/88] Filter: Converted FI_PRINT and FI_PATHMASK_CONSTRUCT to VARARG --- filter/config.Y | 2 +- filter/decl.m4 | 63 ++++++++++++++++++++++++++++++------------- filter/f-inst.c | 72 ++++++++++--------------------------------------- filter/filter.c | 7 ++--- 4 files changed, 63 insertions(+), 81 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index f3e83cfd..9a240763 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -828,7 +828,7 @@ constructor: '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); } - | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); } + | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index b1cdaf0d..d8bbf2bc 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -93,25 +93,6 @@ FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 FID_INTERPRET_BODY') -m4_define(FID_MEMBER_IN, `m4_dnl -FID_LINE_IN()m4_dnl - $1 $2; -FID_STRUCT_IN()m4_dnl - $1 $2; -FID_LINEARIZE_BODY()m4_dnl -item->$2 = whati->$2; -m4_ifelse($3,,,[[ -FID_SAME_BODY()m4_dnl -if ($3) return 0; -]]) -m4_ifelse($4,,,[[ -FID_DUMP_BODY()m4_dnl -debug("%s$4\n", INDENT, $5); -]]) -FID_INTERPRET_EXEC()m4_dnl -const $1 $2 = whati->$2 -FID_INTERPRET_BODY') - # Instruction arguments are needed only until linearization is done. # This puts the arguments into the filter line to be executed before # the instruction itself. @@ -136,6 +117,48 @@ FID_LINEARIZE_BODY pos = linearize(dest, whati->f$1, pos); FID_INTERPRET_BODY()') +# Some instructions accept variable number of arguments. +m4_define(VARARG, ` +FID_NEW_ARGS()m4_dnl + , struct f_inst * fvar +FID_STRUCT_IN()m4_dnl + struct f_inst * fvar; + uint varcount; +FID_LINE_IN()m4_dnl + uint varcount; +FID_NEW_BODY()m4_dnl +whati->varcount = 0; +whati->fvar = fvar; +for (const struct f_inst *child = fvar; child; child = child->next, whati->varcount++) { + what->size += child->size; +FID_IFCONST([[ + if (child->fi_code != FI_CONSTANT) + constargs = 0; +]]) +} +FID_IFCONST([[ + const struct f_inst **items = NULL; + if (constargs) { + items = alloca(whati->varcount * sizeof(struct f_inst *)); + const struct f_inst *child = fvar; + for (uint i=0; child; i++) + child = (items[i] = child)->next; + } +]]) +FID_LINEARIZE_BODY()m4_dnl + pos = linearize(dest, whati->fvar, pos); + item->varcount = whati->varcount; +FID_DUMP_BODY()m4_dnl + debug("%snumber of varargs %u\n", INDENT, item->varcount); +FID_SAME_BODY()m4_dnl + if (f1->varcount != f2->varcount) return 0; +FID_INTERPRET_BODY() +FID_HIC(,[[ + if (fstk->vcnt < whati->varcount) runtime("Stack underflow"); + fstk->vcnt -= whati->varcount; +]],) +') + # Some arguments need to check their type. After that, ARG_ANY is called. m4_define(ARG, `ARG_ANY($1) FID_INTERPRET_EXEC()m4_dnl @@ -410,6 +433,7 @@ fi_constant(struct f_inst *what, struct f_val val) #define v1 whati->f1->i_FI_CONSTANT.val #define v2 whati->f2->i_FI_CONSTANT.val #define v3 whati->f3->i_FI_CONSTANT.val +#define vv(i) items[i]->i_FI_CONSTANT.val #define runtime(fmt, ...) cf_error("filter preevaluation, line %d: " fmt, ifs->lino, ##__VA_ARGS__) #define fpool cfg_mem #define falloc(size) cfg_alloc(size) @@ -418,6 +442,7 @@ FID_WR_PUT(3) #undef v1 #undef v2 #undef v3 +#undef vv /* Line dumpers */ #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) diff --git a/filter/f-inst.c b/filter/f-inst.c index 7d41efe6..f1304833 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -60,8 +60,9 @@ * * What is the syntax here? * m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args - * m4_dnl ARG(num, type); argument, its id (in data fields) and type - * m4_dnl ARG_ANY(num); argument with no type check + * m4_dnl ARG(num, type); argument, its id (in data fields) and type accessible by v1, v2, v3 + * m4_dnl ARG_ANY(num); argument with no type check accessible by v1, v2, v3 + * m4_dnl VARARG; variable-length argument list; accessible by vv(i) and whati->varcount * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line * m4_dnl SYMBOL; symbol handed from config * m4_dnl STATIC_ATTR; static attribute definition @@ -297,45 +298,19 @@ } INST(FI_PATHMASK_CONSTRUCT, 0, 1) { - ARG_ANY(1); - FID_MEMBER(uint, count, f1->count != f2->count, number of items %u, item->count); + VARARG; - FID_NEW_BODY - uint len = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++); + struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->varcount * sizeof(struct f_path_mask_item)); + pm->len = whati->varcount; - whati->count = len; - struct f_inst **items; - if (constargs) { - items = alloca(len * sizeof(struct f_inst *)); - for (uint i=0; f1; i++) { - items[i] = f1; - f1 = f1->next; - items[i]->next = 0; - } - whati->f1 = NULL; - } - FID_INTERPRET_BODY - - FID_INTERPRET_EXEC - if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ - runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); - -#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] - - FID_INTERPRET_NEW -#define pv(i) items[i]->i_FI_CONSTANT.val - - FID_INTERPRET_BODY - struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); - for (uint i=0; icount; i++) { - switch (pv(i).type) { + for (uint i=0; ivarcount; i++) { + switch (vv(i).type) { case T_PATH_MASK_ITEM: - pm->item[i] = pv(i).val.pmi; + pm->item[i] = vv(i).val.pmi; break; case T_INT: pm->item[i] = (struct f_path_mask_item) { - .asn = pv(i).val.i, + .asn = vv(i).val.i, .kind = PM_ASN, }; break; @@ -343,13 +318,7 @@ runtime( "Error resolving path mask template: value not an integer" ); } } -#undef pv - FID_INTERPRET_EXEC - fstk->vcnt -= whati->count; - FID_INTERPRET_BODY - - pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); } @@ -479,24 +448,11 @@ INST(FI_PRINT, 0, 0) { NEVER_CONSTANT; - ARG_ANY(1); - FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count); + VARARG; - FID_NEW_BODY - uint len = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) - ; - whati->count = len; - - FID_INTERPRET_BODY - -#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] - if (whati->count && !(fs->flags & FF_SILENT)) - for (uint i=0; icount; i++) - val_format(&(pv(i)), &fs->buf); -#undef pv - - fstk->vcnt -= whati->count; + if (whati->varcount && !(fs->flags & FF_SILENT)) + for (uint i=0; ivarcount; i++) + val_format(&(vv(i)), &fs->buf); } INST(FI_DIE, 0, 0) { diff --git a/filter/filter.c b/filter/filter.c index 0d727449..2aa2f629 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -190,9 +190,10 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) switch (what->fi_code) { #define res fstk->vstk[fstk->vcnt] -#define v1 fstk->vstk[fstk->vcnt] -#define v2 fstk->vstk[fstk->vcnt + 1] -#define v3 fstk->vstk[fstk->vcnt + 2] +#define vv(i) fstk->vstk[fstk->vcnt + (i)] +#define v1 vv(0) +#define v2 vv(1) +#define v3 vv(2) #define runtime(fmt, ...) do { \ if (!(fs->flags & FF_SILENT)) \ From f634adc7dcf8cfc2a8ea8a61fe2f85d8aadf5a75 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 15:17:04 +0200 Subject: [PATCH 86/88] Filter: FID_MEMBER debug string is a C constant string --- filter/decl.m4 | 6 +++--- filter/f-inst.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/filter/decl.m4 b/filter/decl.m4 index d8bbf2bc..4d5b70dc 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -87,7 +87,7 @@ if ($3) return 0; ]]) m4_ifelse($4,,,[[ FID_DUMP_BODY()m4_dnl -debug("%s$4\n", INDENT, $5); +debug("%s" $4 "\n", INDENT, $5); ]]) FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 @@ -208,8 +208,8 @@ m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]], m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') # Some common filter instruction members -m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)') -m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)') +m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)') +m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())') diff --git a/filter/f-inst.c b/filter/f-inst.c index f1304833..997bc6ac 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -253,7 +253,7 @@ 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; @@ -431,7 +431,7 @@ struct f_val, val, [[ !val_same(&(f1->val), &(f2->val)) ]], - value %s, + "value %s", val_dump(&(item->val)) ); @@ -457,7 +457,7 @@ INST(FI_DIE, 0, 0) { NEVER_CONSTANT; - FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret)); + FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, "%s", filter_return_str(item->fret)); if (fs->buf.start < fs->buf.pos) log_commit(*L_INFO, &fs->buf); @@ -909,7 +909,7 @@ 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) { @@ -1161,7 +1161,7 @@ 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); From 3782454e8dead1184e698fa84f7491182b54454e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 15:23:35 +0200 Subject: [PATCH 87/88] Filter: Simpler filter context allocation --- filter/filter.c | 39 +++++++++++++++++++-------------------- lib/birdlib.h | 6 ++---- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 2aa2f629..35bd75e6 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -93,13 +93,8 @@ struct filter_state { int flags; }; -#if HAVE_THREAD_LOCAL _Thread_local static struct filter_state filter_state; _Thread_local static struct filter_stack filter_stack; -#define FS_INIT(...) filter_state = (struct filter_state) { .stack = &filter_stack, __VA_ARGS__ } -#else -#define FS_INIT(...) struct filter_state filter_state = { .stack = alloca(sizeof(struct filter_stack)), __VA_ARGS__ }; -#endif void (*bt_assert_hook)(int result, const struct f_line_item *assert); @@ -279,11 +274,12 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i DBG( "Running filter `%s'...", filter->name ); /* Initialize the filter state */ - FS_INIT( - .rte = rte, - .pool = tmp_pool, - .flags = flags, - ); + filter_state = (struct filter_state) { + .stack = &filter_stack, + .rte = rte, + .pool = tmp_pool, + .flags = flags, + }; LOG_BUFFER_INIT(filter_state.buf); @@ -342,10 +338,11 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) { - FS_INIT( - .rte = rte, - .pool = tmp_pool, - ); + filter_state = (struct filter_state) { + .stack = &filter_stack, + .rte = rte, + .pool = tmp_pool, + }; LOG_BUFFER_INIT(filter_state.buf); @@ -364,9 +361,10 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) { - FS_INIT( - .pool = tmp_pool, - ); + filter_state = (struct filter_state) { + .stack = &filter_stack, + .pool = tmp_pool, + }; LOG_BUFFER_INIT(filter_state.buf); @@ -383,9 +381,10 @@ uint f_eval_int(const struct f_line *expr) { /* Called independently in parse-time to eval expressions */ - FS_INIT( - .pool = cfg_mem, - ); + filter_state = (struct filter_state) { + .stack = &filter_stack, + .pool = cfg_mem, + }; struct f_val val; diff --git a/lib/birdlib.h b/lib/birdlib.h index 9743da32..30ea433c 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -73,10 +73,8 @@ static inline int u64_cmp(u64 i1, u64 i2) #define UNUSED __attribute__((unused)) #define PACKED __attribute__((packed)) -#ifdef HAVE_THREAD_LOCAL -#define THREAD_LOCAL _Thread_local -#else -#define THREAD_LOCAL +#ifndef HAVE_THREAD_LOCAL +#define _Thread_local #endif /* Microsecond time */ From efd7c87b5bcd476ba74ffe9f369e2f6fe978cbb1 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Jul 2019 15:43:47 +0200 Subject: [PATCH 88/88] Filter: further split of print & die to FI_PRINT, FI_FLUSH and FI_DIE --- filter/config.Y | 28 ++++++++++++++-------------- filter/f-inst.c | 17 +++++++++-------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 9a240763..83319194 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -966,8 +966,6 @@ break_command: | ACCEPT { $$ = F_ACCEPT; } | REJECT { $$ = F_REJECT; } | ERROR { $$ = F_ERROR; } - | PRINT { $$ = F_NOP; } - | PRINTN { $$ = F_NONL; } ; print_list: /* EMPTY */ { $$ = NULL; } @@ -1018,21 +1016,23 @@ cmd: $$ = f_new_inst(FI_EA_UNSET, $3); } | break_command print_list ';' { - struct f_inst *breaker = NULL; - struct f_inst *printer = NULL; - if ($2) - printer = f_new_inst(FI_PRINT, $2); - if ($1 != F_NONL) - breaker = f_new_inst(FI_DIE, $1); - - if (printer && breaker) - printer->next = breaker; - - if (printer) + struct f_inst *breaker = f_new_inst(FI_DIE, $1); + if ($2) { + struct f_inst *printer = f_new_inst(FI_PRINT, $2); + struct f_inst *flusher = f_new_inst(FI_FLUSH); + printer->next = flusher; + flusher->next = breaker; $$ = printer; - else + } else $$ = breaker; } + | PRINT print_list ';' { + $$ = f_new_inst(FI_PRINT, $2); + $$->next = f_new_inst(FI_FLUSH); + } + | PRINTN print_list ';' { + $$ = f_new_inst(FI_PRINT, $2); + } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } | CASE term '{' switch_body '}' { $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); diff --git a/filter/f-inst.c b/filter/f-inst.c index 997bc6ac..0867ac4a 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -455,23 +455,24 @@ val_format(&(vv(i)), &fs->buf); } + INST(FI_FLUSH, 0, 0) { + NEVER_CONSTANT; + 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)); - if (fs->buf.start < fs->buf.pos) - log_commit(*L_INFO, &fs->buf); - 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"); }