diff --git a/filter/data.c b/filter/data.c index cb52b499..de745654 100644 --- a/filter/data.c +++ b/filter/data.c @@ -58,6 +58,7 @@ static const char * const f_type_str[] = { [T_RD] = "rd", [T_ROUTE] = "route", + [T_ROUTES_BLOCK] = "block of routes", }; const char * @@ -80,6 +81,7 @@ f_type_element_type(enum f_type t) case T_CLIST: return T_PAIR; case T_ECLIST: return T_EC; case T_LCLIST: return T_LC; + case T_ROUTES_BLOCK: return T_ROUTE; default: return T_VOID; }; } @@ -209,6 +211,7 @@ val_compare(const struct f_val *v1, const struct f_val *v2) case T_STRING: return strcmp(v1->val.s, v2->val.s); case T_ROUTE: + case T_ROUTES_BLOCK: default: return F_CMP_ERROR; } @@ -301,6 +304,15 @@ val_same(const struct f_val *v1, const struct f_val *v2) return trie_same(v1->val.ti, v2->val.ti); case T_ROUTE: return rte_same(v1->val.rte, v2->val.rte); + case T_ROUTES_BLOCK: + for ( + rte *r1 = v1->val.rte, *r2 = v2->val.rte; + r1 || r2; + r1 = r1->next, r2 = r2->next + ) + if (!r1 || !r2 || !rte_same(r1, r2)) + return 0; + return 1; default: bug("Invalid type in val_same(): %x", v1->type); } @@ -589,6 +601,19 @@ rte_format(const struct rte *rte, buffer *buf) buffer_puts(buf, "[No route]"); } +static void +rte_block_format(const struct rte *rte, buffer *buf) +{ + buffer_print(buf, "Block of routes:"); + + for (int i = 0; rte; rte = rte->next, i++) + { + buffer_print(buf, "%s%d: ", i ? "; " : " ", i); + rte_format(rte, buf); + } +} + + /* * val_format - format filter value */ @@ -619,6 +644,7 @@ val_format(const struct f_val *v, buffer *buf) 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; case T_ROUTE: rte_format(v->val.rte, buf); return; + case T_ROUTES_BLOCK: rte_block_format(v->val.rte, buf); return; default: buffer_print(buf, "[unknown type %x]", v->type); return; } } diff --git a/filter/data.h b/filter/data.h index 620a80bf..103591b7 100644 --- a/filter/data.h +++ b/filter/data.h @@ -63,6 +63,7 @@ enum f_type { T_BYTESTRING = 0x2c, T_ROUTE = 0x78, + T_ROUTES_BLOCK = 0x79, T_SET = 0x80, T_PREFIX_SET = 0x81, } PACKED; diff --git a/filter/f-inst.c b/filter/f-inst.c index 76ec272d..42e38a4b 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -617,6 +617,34 @@ METHOD_CONSTRUCTOR("!for_next"); } + INST(FI_ROUTES_BLOCK_FOR_NEXT, 3, 0) { + NEVER_CONSTANT; + ARG(1, T_ROUTES_BLOCK); + + /* Loop auxiliary variable is initialized to T_VOID. + * In the first run, we initialize the auxiliary variable + * to the routes block supplied. It changes its type + * to T_ROUTES_BLOCK and therefore won't be run again. */ + if (v2.type == T_VOID) + v2 = v1; + + if (v2.val.rte) + { + /* There is some route to process, set it into the iterator variable. + * Its type has been already initialized by f_for_cycle(). */ + v3.val.rte = v2.val.rte; + v3.val.eattrs = v3.val.rte->attrs->eattrs; + + /* Prepare next route in the loop auxiliary variable */ + v2.val.rte = v2.val.rte->next; + + /* And execute the line */ + LINE(2,0); + } + + METHOD_CONSTRUCTOR("!for_next"); + } + INST(FI_CONDITION, 1, 0) { ARG(1, T_BOOL); if (v1.val.i)