From 315f23a0470112ced04badbb117bc7854ee53e06 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 9 May 2015 18:50:15 +0200 Subject: Add bitfield route attribute type --- filter/filter.c | 82 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 25 deletions(-) (limited to 'filter') diff --git a/filter/filter.c b/filter/filter.c index a4f12330..3b14fc0c 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -462,7 +462,7 @@ static int f_flags; static inline void f_rte_cow(void) { - *f_rte = rte_cow(*f_rte); + *f_rte = rte_cow(*f_rte); } /* @@ -479,7 +479,7 @@ f_rta_cow(void) /* Store old rta to free it later */ f_old_rta = (*f_rte)->attrs; - /* + /* * Alloc new rta, do shallow copy and update rte. Fields eattrs * and nexthops of rta are shared with f_old_rta (they will be * copied when the cached rta will be obtained at the end of @@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define ACCESS_RTE \ do { if (!f_rte) runtime("No route to access"); } while (0) +#define BITFIELD_MASK(what) \ + (1u << (what->a2.i >> 24)) + /** * interpret * @what: filter to interpret @@ -526,7 +529,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; * Each instruction has 4 fields: code (which is instruction code), * aux (which is extension to instruction code, typically type), * arg1 and arg2 - arguments. Depending on instruction, arguments - * are either integers, or pointers to instruction trees. Common + * 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. * @@ -585,7 +588,7 @@ interpret(struct f_inst *what) default: runtime( "Usage of unknown type" ); } break; - + case '&': case '|': ARG(v1, a1.p); @@ -625,7 +628,7 @@ interpret(struct f_inst *what) 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; } @@ -724,7 +727,7 @@ interpret(struct f_inst *what) #endif runtime( "Assigning to variable of incompatible type" ); } - *vp = v2; + *vp = v2; break; /* some constants have value in a2, some in *a1.p, strange. */ @@ -864,12 +867,14 @@ interpret(struct f_inst *what) ACCESS_RTE; { eattr *e = NULL; + u16 code = what->a2.i; + if (!(f_flags & FF_FORCE_TMPATTR)) - e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); - if (!e) - e = ea_find( (*f_tmp_attrs), what->a2.i ); + e = ea_find((*f_rte)->attrs->eattrs, code); + if (!e) + e = ea_find((*f_tmp_attrs), code); if ((!e) && (f_flags & FF_FORCE_TMPATTR)) - e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); + e = ea_find((*f_rte)->attrs->eattrs, code); if (!e) { /* A special case: undefined int_set looks like empty int_set */ @@ -878,8 +883,9 @@ interpret(struct f_inst *what) res.val.ad = adata_empty(f_pool, 0); break; } + /* The same special case for ec_set */ - else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { res.type = T_ECLIST; res.val.ad = adata_empty(f_pool, 0); break; @@ -912,6 +918,10 @@ interpret(struct f_inst *what) 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; @@ -933,13 +943,15 @@ interpret(struct f_inst *what) ONEARG; { struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); + u16 code = what->a2.i; l->next = NULL; l->flags = EALF_SORTED; l->count = 1; - l->attrs[0].id = what->a2.i; + l->attrs[0].id = code; l->attrs[0].flags = 0; l->attrs[0].type = what->aux | EAF_ORIGINATED; + switch (what->aux & EAF_TYPE_MASK) { case EAF_TYPE_INT: if (v1.type != T_INT) @@ -978,6 +990,26 @@ interpret(struct f_inst *what) 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 = NULL; + if (!(f_flags & FF_FORCE_TMPATTR)) + e = ea_find((*f_rte)->attrs->eattrs, code); + if (!e) + e = ea_find((*f_tmp_attrs), code); + if ((!e) && (f_flags & FF_FORCE_TMPATTR)) + e = ea_find((*f_rte)->attrs->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" ); @@ -1073,7 +1105,7 @@ interpret(struct f_inst *what) res = interpret(what->a2.p); if (res.type == T_RETURN) return res; - res.type &= ~T_RETURN; + res.type &= ~T_RETURN; break; case P('c','v'): /* Clear local variables */ for (sym = what->a1.p; sym != NULL; sym = sym->aux2) @@ -1090,7 +1122,7 @@ interpret(struct f_inst *what) debug( "No else statement?\n"); break; } - } + } /* It is actually possible to have t->data NULL */ res = interpret(t->data); @@ -1184,10 +1216,10 @@ interpret(struct f_inst *what) runtime("Can't add set"); else if (!arg_set) res.val.ad = int_set_add(f_pool, v1.val.ad, n); - else + else res.val.ad = int_set_union(f_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); @@ -1209,7 +1241,7 @@ interpret(struct f_inst *what) { /* 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; @@ -1226,10 +1258,10 @@ interpret(struct f_inst *what) runtime("Can't add set"); else if (!arg_set) res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec); - else + else res.val.ad = ec_set_union(f_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); @@ -1353,7 +1385,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) } break; - case 'c': + case 'c': switch (f1->aux) { case T_PREFIX_SET: @@ -1381,7 +1413,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) return 0; break; - case 'V': + case 'V': if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) return 0; break; @@ -1399,12 +1431,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) case 'r': ONEARG; break; case P('c','p'): ONEARG; break; case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ - ONEARG; + ONEARG; if (!i_same(f1->a2.p, f2->a2.p)) - return 0; + return 0; f2->a2.p = f1->a2.p; break; - case P('c','v'): break; /* internal instruction */ + case P('c','v'): break; /* internal instruction */ case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; case P('i','M'): TWOARGS; break; case P('A','p'): TWOARGS; break; @@ -1414,7 +1446,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) case P('R','C'): TWOARGS; /* Does not really make sense - ROA check resuls may change anyway */ - if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, + if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, ((struct f_inst_roa_check *) f2)->rtc->name)) return 0; break; -- cgit v1.2.3